summary refs log tree commit diff
diff options
context:
space:
mode:
authorDavid Tolnay <dtolnay@chromium.org>2018-12-06 17:58:09 -0800
committerchrome-bot <chrome-bot@chromium.org>2018-12-09 00:48:17 -0800
commit3c0aac44d7d7150bbfb2981b92a4ed98a64a1a49 (patch)
treebd83bc797de92ebf1d9592c2e740f798160b2c73
parentf97991985d6921375eb5a533c49fd7df5a75d2cd (diff)
downloadcrosvm-3c0aac44d7d7150bbfb2981b92a4ed98a64a1a49.tar
crosvm-3c0aac44d7d7150bbfb2981b92a4ed98a64a1a49.tar.gz
crosvm-3c0aac44d7d7150bbfb2981b92a4ed98a64a1a49.tar.bz2
crosvm-3c0aac44d7d7150bbfb2981b92a4ed98a64a1a49.tar.lz
crosvm-3c0aac44d7d7150bbfb2981b92a4ed98a64a1a49.tar.xz
crosvm-3c0aac44d7d7150bbfb2981b92a4ed98a64a1a49.tar.zst
crosvm-3c0aac44d7d7150bbfb2981b92a4ed98a64a1a49.zip
assertions: Add compile-time assertion macro
A static assertion is particularly appropriate when unsafe code relies
on two types to have the same size, or on some type to have a particular
size. This is a pattern I observed in USB code, for example:

https://chromium.googlesource.com/chromiumos/platform/crosvm/+/ff7068402e6cff527a8558adf597b1596f075166/devices/src/usb/xhci/xhci_abi_schema.rs#522

EXAMPLE:

    extern crate assertions;
    use assertions::const_assert;

    fn main() {
        const_assert!(std::mem::size_of::<String>() == 24);
    }

EXAMPLE THAT FAILS TO COMPILE:

    extern crate assertions;
    use assertions::const_assert;

    fn main() {
        // fails to compile:
        const_assert!(std::mem::size_of::<String>() == 8);
    }

FAILURE LOOKS LIKE:

    error[E0271]: type mismatch resolving `<[(); 0] as assertions::Expr>::Value == assertions::True`
     --> src/main.rs:5:5
      |
    5 |     const_assert!(std::mem::size_of::<String>() == 8);
      |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected struct `assertions::True`, found struct `assertions::False`

TEST=`cargo test` the new crate

Change-Id: I6abe36d5a6a4bd4acb1a02e3aa7c1ece5357f007
Reviewed-on: https://chromium-review.googlesource.com/1366819
Commit-Ready: ChromeOS CL Exonerator Bot <chromiumos-cl-exonerator@appspot.gserviceaccount.com>
Tested-by: David Tolnay <dtolnay@chromium.org>
Reviewed-by: Dylan Reid <dgreid@chromium.org>
-rw-r--r--assertions/Cargo.toml4
-rw-r--r--assertions/src/lib.rs47
-rw-r--r--assertions/src/mechanism.rs34
3 files changed, 85 insertions, 0 deletions
diff --git a/assertions/Cargo.toml b/assertions/Cargo.toml
new file mode 100644
index 0000000..36f9beb
--- /dev/null
+++ b/assertions/Cargo.toml
@@ -0,0 +1,4 @@
+[package]
+name = "assertions"
+version = "0.1.0"
+authors = ["The Chromium OS Authors"]
diff --git a/assertions/src/lib.rs b/assertions/src/lib.rs
new file mode 100644
index 0000000..c53c0c4
--- /dev/null
+++ b/assertions/src/lib.rs
@@ -0,0 +1,47 @@
+// Copyright 2018 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+//! Macros that assert properties of code at compile time.
+//!
+//! A static assertion is particularly appropriate when unsafe code relies on
+//! two types to have the same size, or on some type to have a particular size.
+
+#[doc(hidden)]
+pub mod mechanism;
+
+// Re-export so that these types appear with a more concise name in error
+// messages.
+#[doc(hidden)]
+pub use mechanism::*;
+
+/// Macro that fails to compile if a given const expression is not true.
+///
+/// # Example
+///
+/// ```rust
+/// extern crate assertions;
+/// use assertions::const_assert;
+///
+/// fn main() {
+///     const_assert!(std::mem::size_of::<String>() == 24);
+/// }
+/// ```
+///
+/// # Example that fails to compile
+///
+/// ```rust,compile_fail
+/// extern crate assertions;
+/// use assertions::const_assert;
+///
+/// fn main() {
+///     // fails to compile:
+///     const_assert!(std::mem::size_of::<String>() == 8);
+/// }
+/// ```
+#[macro_export]
+macro_rules! const_assert {
+    ($e:expr) => {
+        let _: $crate::Assert<[(); $e as bool as usize]>;
+    };
+}
diff --git a/assertions/src/mechanism.rs b/assertions/src/mechanism.rs
new file mode 100644
index 0000000..e14b91a
--- /dev/null
+++ b/assertions/src/mechanism.rs
@@ -0,0 +1,34 @@
+// Copyright 2018 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+use std::marker::PhantomData;
+
+pub struct True;
+pub struct False;
+
+pub trait Expr {
+    type Value;
+}
+
+impl Expr for [(); 0] {
+    type Value = False;
+}
+
+impl Expr for [(); 1] {
+    type Value = True;
+}
+
+// If the macro instantiates this with `T = [(); 1]` then it compiles successfully.
+//
+// On the other hand if `T = [(); 0]` the user receives an error like the following:
+//
+//    error[E0271]: type mismatch resolving `<[(); 0] as assertions::Expr>::Value == assertions::True`
+//     --> src/main.rs:5:5
+//      |
+//    5 |     const_assert!(std::mem::size_of::<String>() == 8);
+//      |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected struct `assertions::True`, found struct `assertions::False`
+//
+pub struct Assert<T: Expr<Value = True>> {
+    marker: PhantomData<T>,
+}