Repository: bitflags/bitflags
Pull request #280 (2022-05-02 23:03:00)

Add more platform coverage to CI
This PR gets our build back into shape by adding more platform coverage (`bitflags` itself doesn't have platform-dependent code, but its tests do), and ensuring we can build without any prelude.


Patch:
diff --git a/.github/workflows/rust.yml b/.github/workflows/rust.yml
index ffe0eda..b7b2486 100644
--- a/.github/workflows/rust.yml
+++ b/.github/workflows/rust.yml
@@ -7,32 +7,47 @@ env:
 
 jobs:
   check:
-    name: Test
-    runs-on: ubuntu-latest
+    name: "Tests / OS: ${{ matrix.os }} - ${{ matrix.channel }}-${{ matrix.rust_target }}"
+    runs-on: ${{ matrix.os }}
     strategy:
-      fail-fast: true
       matrix:
-        rust:
-          - stable
-          - beta
-          - nightly
-          - 1.46.0
+        exclude:
+        - os: macos-10.15
+          rust_target: x86_64-gnu
+        - os: macos-10.15
+          rust_target: x86_64-msvc
+        - os: windows-2019
+          rust_target: x86_64-apple-darwin
+        - os: ubuntu-20.04
+          rust_target: x86_64-msvc
+        - os: ubuntu-20.04
+          rust_target: x86_64-apple-darwin
+        channel:
+        - stable
+        - beta
+        - nightly
+        os:
+        - macos-10.15
+        - windows-2019
+        - ubuntu-20.04
+        rust_target:
+        - x86_64-gnu
+        - x86_64-msvc
+        - x86_64-apple-darwin
+
     steps:
-      - name: Checkout sources
-        uses: actions/checkout@v2
+    - name: Checkout repository
+      uses: actions/checkout@v2
 
-      - name: Install Rust toolchain
-        uses: actions-rs/toolchain@v1
-        with:
-          profile: minimal
-          toolchain: ${{ matrix.rust }}
-          override: true
+    - name: Install Rust Toolchain
+      uses: actions-rs/toolchain@v1
+      with:
+        override: true
+        profile: minimal
+        toolchain: ${{ matrix.channel }}-${{ matrix.rust_target }}
 
-      - name: Default features
-        uses: actions-rs/cargo@v1
-        with:
-          command: test
-          args: --features example_generated
+    - name: Tests
+      run: cargo test --features example_generated
 
   embedded:
     name: Build (embedded)
diff --git a/Cargo.toml b/Cargo.toml
index 4476122..9c7c7aa 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -25,13 +25,11 @@ compiler_builtins = { version = '0.1.2', optional = true }
 [dev-dependencies]
 trybuild = "1.0"
 rustversion = "1.0"
-walkdir = "2.3"
 serde = "1.0"
 serde_derive = "1.0"
 serde_json = "1.0"
 
 [features]
-default = []
 example_generated = []
 rustc-dep-of-std = ["core", "compiler_builtins"]
 
diff --git a/bors.toml b/bors.toml
deleted file mode 100644
index 867e8a5..0000000
--- a/bors.toml
+++ /dev/null
@@ -1,3 +0,0 @@
-status = [
-	"rust",
-]
diff --git a/src/lib.rs b/src/lib.rs
index b9d77f7..a2d3193 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -278,9 +278,6 @@
 #![cfg_attr(not(test), no_std)]
 #![doc(html_root_url = "https://docs.rs/bitflags/1.3.2")]
 
-#[doc(hidden)]
-pub extern crate core as _core;
-
 #[doc(inline)]
 pub use bitflags_trait::BitFlags;
 
@@ -288,6 +285,7 @@ mod bitflags_trait;
 
 #[doc(hidden)]
 pub mod __private {
+    pub use core;
     pub use crate::bitflags_trait::ImplementedByBitFlagsMacro;
 }
 
@@ -407,6 +405,7 @@ macro_rules! __impl_all_bitflags {
         #[allow(non_snake_case)]
         trait __BitFlags {
             $(
+                #[allow(deprecated)]
                 const $Flag: $T = 0;
             )+
         }
@@ -440,86 +439,59 @@ macro_rules! __impl_bitflags {
             )*
         }
     ) => {
-        impl $crate::_core::fmt::Debug for $BitFlags {
-            fn fmt(&self, f: &mut $crate::_core::fmt::Formatter) -> $crate::_core::fmt::Result {
-                // This convoluted approach is to handle #[cfg]-based flag
-                // omission correctly. For example it needs to support:
-                //
-                //    #[cfg(unix)] const A: Flag = /* ... */;
-                //    #[cfg(windows)] const B: Flag = /* ... */;
-
-                // Unconditionally define a check for every flag, even disabled
-                // ones.
-                #[allow(non_snake_case)]
-                trait __BitFlags {
-                    $(
-                        #[inline]
-                        fn $Flag(&self) -> bool { false }
-                    )*
-                }
+        impl $crate::__private::core::fmt::Debug for $BitFlags {
+            fn fmt(&self, f: &mut $crate::__private::core::fmt::Formatter) -> $crate::__private::core::fmt::Result {
+                // Iterate over the valid flags
+                let mut first = true;
+                for (name, _) in self.iter() {
+                    if !first {
+                        f.write_str(" | ")?;
+                    }
 
-                // Conditionally override the check for just those flags that
-                // are not #[cfg]ed away.
-                #[allow(non_snake_case)]
-                impl __BitFlags for $BitFlags {
-                    $(
-                        __impl_bitflags! {
-                            #[allow(deprecated)]
-                            #[inline]
-                            $(? #[$attr $($args)*])*
-                            fn $Flag(&self) -> bool {
-                                if Self::$Flag.bits == 0 && self.bits != 0 {
-                                    false
-                                } else {
-                                    self.bits & Self::$Flag.bits == Self::$Flag.bits
-                                }
-                            }
-                        }
-                    )*
+                    first = false;
+                    f.write_str(name)?;
                 }
 
-                let mut first = true;
-                $(
-                    if <Self as __BitFlags>::$Flag(self) {
-                        if !first {
-                            f.write_str(" | ")?;
-                        }
-                        first = false;
-                        f.write_str($crate::_core::stringify!($Flag))?;
-                    }
-                )*
+                // Append any extra bits that correspond to flags to the end of the format
                 let extra_bits = self.bits & !Self::all().bits();
+
                 if extra_bits != 0 {
                     if !first {
                         f.write_str(" | ")?;
                     }
                     first = false;
-                    $crate::_core::write!(f, "{:#x}", extra_bits)?;
+                    $crate::__private::core::write!(f, "{:#x}", extra_bits)?;
                 }
+
                 if first {
                     f.write_str("(empty)")?;
                 }
-                $crate::_core::fmt::Result::Ok(())
+
+                $crate::__private::core::fmt::Result::Ok(())
             }
         }
-        impl $crate::_core::fmt::Binary for $BitFlags {
-            fn fmt(&self, f: &mut $crate::_core::fmt::Formatter) -> $crate::_core::fmt::Result {
-                $crate::_core::fmt::Binary::fmt(&self.bits, f)
+
+        impl $crate::__private::core::fmt::Binary for $BitFlags {
+            fn fmt(&self, f: &mut $crate::__private::core::fmt::Formatter) -> $crate::__private::core::fmt::Result {
+                $crate::__private::core::fmt::Binary::fmt(&self.bits, f)
             }
         }
-        impl $crate::_core::fmt::Octal for $BitFlags {
-            fn fmt(&self, f: &mut $crate::_core::fmt::Formatter) -> $crate::_core::fmt::Result {
-                $crate::_core::fmt::Octal::fmt(&self.bits, f)
+
+        impl $crate::__private::core::fmt::Octal for $BitFlags {
+            fn fmt(&self, f: &mut $crate::__private::core::fmt::Formatter) -> $crate::__private::core::fmt::Result {
+                $crate::__private::core::fmt::Octal::fmt(&self.bits, f)
             }
         }
-        impl $crate::_core::fmt::LowerHex for $BitFlags {
-            fn fmt(&self, f: &mut $crate::_core::fmt::Formatter) -> $crate::_core::fmt::Result {
-                $crate::_core::fmt::LowerHex::fmt(&self.bits, f)
+
+        impl $crate::__private::core::fmt::LowerHex for $BitFlags {
+            fn fmt(&self, f: &mut $crate::__private::core::fmt::Formatter) -> $crate::__private::core::fmt::Result {
+                $crate::__private::core::fmt::LowerHex::fmt(&self.bits, f)
             }
         }
-        impl $crate::_core::fmt::UpperHex for $BitFlags {
-            fn fmt(&self, f: &mut $crate::_core::fmt::Formatter) -> $crate::_core::fmt::Result {
-                $crate::_core::fmt::UpperHex::fmt(&self.bits, f)
+
+        impl $crate::__private::core::fmt::UpperHex for $BitFlags {
+            fn fmt(&self, f: &mut $crate::__private::core::fmt::Formatter) -> $crate::__private::core::fmt::Result {
+                $crate::__private::core::fmt::UpperHex::fmt(&self.bits, f)
             }
         }
 
@@ -558,12 +530,12 @@ macro_rules! __impl_bitflags {
             /// Convert from underlying bit representation, unless that
             /// representation contains bits that do not correspond to a flag.
             #[inline]
-            pub const fn from_bits(bits: $T) -> $crate::_core::option::Option<Self> {
+            pub const fn from_bits(bits: $T) -> $crate::__private::core::option::Option<Self> {
                 let truncated = Self::from_bits_truncate(bits).bits;
                 if truncated == bits {
-                    Some(Self{ bits })
+                    $crate::__private::core::option::Option::Some(Self{ bits })
                 } else {
-                    None
+                    $crate::__private::core::option::Option::None
                 }
             }
 
@@ -572,7 +544,7 @@ macro_rules! __impl_bitflags {
             #[inline]
             pub const fn from_bits_truncate(bits: $T) -> Self {
                 if bits == 0 {
-                    return Self{ bits }
+                    return Self { bits }
                 }
 
                 #[allow(unused_mut)]
@@ -746,50 +718,10 @@ macro_rules! __impl_bitflags {
                 Self::from_bits_truncate(!self.bits)
             }
 
-            /// Returns an iterator over all the flags in this set.
-            pub fn iter(mut self) -> impl Iterator<Item = Self> {
-                const NUM_FLAGS: usize = {
-                    #[allow(unused_mut)]
-                    let mut num_flags = 0;
-
-                    $(
-                        #[allow(unused_doc_comments, unused_attributes)]
-                        $(#[$attr $($args)*])*
-                        {
-                            num_flags += 1;
-                        }
-                    )*
+            /// Returns an iterator over set flags and their names.
+            pub fn iter(mut self) -> impl $crate::__private::core::iter::Iterator<Item = (&'static str, Self)> {
+                use $crate::__private::core::iter::Iterator as _;
 
-                    num_flags
-                };
-                const OPTIONS: [$BitFlags; NUM_FLAGS] = [
-                    $(
-                        #[allow(unused_doc_comments, unused_attributes)]
-                        $(#[$attr $($args)*])*
-                        $BitFlags::$Flag,
-                    )*
-                ];
-                let mut start = 0;
-
-                $crate::_core::iter::from_fn(move || {
-                    if self.is_empty() || NUM_FLAGS == 0 {
-                        None
-                    }else{
-                        for flag in OPTIONS[start..NUM_FLAGS].iter().copied() {
-                            start += 1;
-                            if self.contains(flag) {
-                                self.remove(flag);
-                                return Some(flag)
-                            }
-                        }
-
-                        None
-                    }
-                })
-            }
-
-            /// Returns an iterator over all the flags names as &'static str in this set.
-            pub fn iter_names(mut self) -> impl Iterator<Item = &'static str> {
                 const NUM_FLAGS: usize = {
                     #[allow(unused_mut)]
                     let mut num_flags = 0;
@@ -804,6 +736,7 @@ macro_rules! __impl_bitflags {
 
                     num_flags
                 };
+
                 const OPTIONS: [$BitFlags; NUM_FLAGS] = [
                     $(
                         #[allow(unused_doc_comments, unused_attributes)]
@@ -811,37 +744,40 @@ macro_rules! __impl_bitflags {
                         $BitFlags::$Flag,
                     )*
                 ];
+
                 #[allow(unused_doc_comments, unused_attributes)]
                 const OPTIONS_NAMES: [&'static str; NUM_FLAGS] = [
                     $(
                         $(#[$attr $($args)*])*
-                        $crate::_core::stringify!($Flag),
+                        $crate::__private::core::stringify!($Flag),
                     )*
                 ];
+
                 let mut start = 0;
 
-                $crate::_core::iter::from_fn(move || {
+                $crate::__private::core::iter::from_fn(move || {
                     if self.is_empty() || NUM_FLAGS == 0 {
-                        None
-                    }else{
+                        $crate::__private::core::option::Option::None
+                    } else {
                         for (flag, flag_name) in OPTIONS[start..NUM_FLAGS].iter().copied()
                             .zip(OPTIONS_NAMES[start..NUM_FLAGS].iter().copied())
                         {
                             start += 1;
                             if self.contains(flag) {
                                 self.remove(flag);
-                                return Some(flag_name)
+
+                                return $crate::__private::core::option::Option::Some((flag_name, flag))
                             }
                         }
 
-                        None
+                        $crate::__private::core::option::Option::None
                     }
                 })
             }
 
         }
 
-        impl $crate::_core::ops::BitOr for $BitFlags {
+        impl $crate::__private::core::ops::BitOr for $BitFlags {
             type Output = Self;
 
             /// Returns the union of the two sets of flags.
@@ -851,7 +787,7 @@ macro_rules! __impl_bitflags {
             }
         }
 
-        impl $crate::_core::ops::BitOrAssign for $BitFlags {
+        impl $crate::__private::core::ops::BitOrAssign for $BitFlags {
             /// Adds the set of flags.
             #[inline]
             fn bitor_assign(&mut self, other: Self) {
@@ -859,7 +795,7 @@ macro_rules! __impl_bitflags {
             }
         }
 
-        impl $crate::_core::ops::BitXor for $BitFlags {
+        impl $crate::__private::core::ops::BitXor for $BitFlags {
             type Output = Self;
 
             /// Returns the left flags, but with all the right flags toggled.
@@ -869,7 +805,7 @@ macro_rules! __impl_bitflags {
             }
         }
 
-        impl $crate::_core::ops::BitXorAssign for $BitFlags {
+        impl $crate::__private::core::ops::BitXorAssign for $BitFlags {
             /// Toggles the set of flags.
             #[inline]
             fn bitxor_assign(&mut self, other: Self) {
@@ -877,7 +813,7 @@ macro_rules! __impl_bitflags {
             }
         }
 
-        impl $crate::_core::ops::BitAnd for $BitFlags {
+        impl $crate::__private::core::ops::BitAnd for $BitFlags {
             type Output = Self;
 
             /// Returns the intersection between the two sets of flags.
@@ -887,7 +823,7 @@ macro_rules! __impl_bitflags {
             }
         }
 
-        impl $crate::_core::ops::BitAndAssign for $BitFlags {
+        impl $crate::__private::core::ops::BitAndAssign for $BitFlags {
             /// Disables all flags disabled in the set.
             #[inline]
             fn bitand_assign(&mut self, other: Self) {
@@ -895,7 +831,7 @@ macro_rules! __impl_bitflags {
             }
         }
 
-        impl $crate::_core::ops::Sub for $BitFlags {
+        impl $crate::__private::core::ops::Sub for $BitFlags {
             type Output = Self;
 
             /// Returns the set difference of the two sets of flags.
@@ -905,7 +841,7 @@ macro_rules! __impl_bitflags {
             }
         }
 
-        impl $crate::_core::ops::SubAssign for $BitFlags {
+        impl $crate::__private::core::ops::SubAssign for $BitFlags {
             /// Disables all flags enabled in the set.
             #[inline]
             fn sub_assign(&mut self, other: Self) {
@@ -913,7 +849,7 @@ macro_rules! __impl_bitflags {
             }
         }
 
-        impl $crate::_core::ops::Not for $BitFlags {
+        impl $crate::__private::core::ops::Not for $BitFlags {
             type Output = Self;
 
             /// Returns the complement of this set of flags.
@@ -923,16 +859,18 @@ macro_rules! __impl_bitflags {
             }
         }
 
-        impl $crate::_core::iter::Extend<$BitFlags> for $BitFlags {
-            fn extend<T: $crate::_core::iter::IntoIterator<Item=Self>>(&mut self, iterator: T) {
+        impl $crate::__private::core::iter::Extend<$BitFlags> for $BitFlags {
+            fn extend<T: $crate::__private::core::iter::IntoIterator<Item=Self>>(&mut self, iterator: T) {
                 for item in iterator {
                     self.insert(item)
                 }
             }
         }
 
-        impl $crate::_core::iter::FromIterator<$BitFlags> for $BitFlags {
-            fn from_iter<T: $crate::_core::iter::IntoIterator<Item=Self>>(iterator: T) -> Self {
+        impl $crate::__private::core::iter::FromIterator<$BitFlags> for $BitFlags {
+            fn from_iter<T: $crate::__private::core::iter::IntoIterator<Item=Self>>(iterator: T) -> Self {
+                use $crate::__private::core::iter::Extend;
+
                 let mut result = Self::empty();
                 result.extend(iterator);
                 result
@@ -954,7 +892,7 @@ macro_rules! __impl_bitflags {
                 $BitFlags::bits(self)
             }
 
-            fn from_bits(bits: $T) -> $crate::_core::option::Option<$BitFlags> {
+            fn from_bits(bits: $T) -> $crate::__private::core::option::Option<$BitFlags> {
                 $BitFlags::from_bits(bits)
             }
 
@@ -1670,14 +1608,14 @@ mod tests {
     fn test_debug() {
         assert_eq!(format!("{:?}", Flags::A | Flags::B), "A | B");
         assert_eq!(format!("{:?}", Flags::empty()), "(empty)");
-        assert_eq!(format!("{:?}", Flags::ABC), "A | B | C | ABC");
+        assert_eq!(format!("{:?}", Flags::ABC), "A | B | C");
         let extra = unsafe { Flags::from_bits_unchecked(0xb8) };
         assert_eq!(format!("{:?}", extra), "0xb8");
         assert_eq!(format!("{:?}", Flags::A | extra), "A | 0xb8");
 
         assert_eq!(
             format!("{:?}", Flags::ABC | extra),
-            "A | B | C | ABC | 0xb8"
+            "A | B | C | 0xb8"
         );
 
         assert_eq!(format!("{:?}", EmptyFlags::empty()), "(empty)");
@@ -1836,8 +1774,8 @@ mod tests {
         assert!(Flags::SOME.contains(Flags::NONE));
         assert!(Flags::NONE.is_empty());
 
-        assert_eq!(format!("{:?}", Flags::empty()), "NONE");
-        assert_eq!(format!("{:?}", Flags::SOME), "SOME");
+        assert_eq!(format!("{:?}", Flags::empty()), "(empty)");
+        assert_eq!(format!("{:?}", Flags::SOME), "NONE | SOME");
     }
 
     #[test]
@@ -1867,7 +1805,7 @@ mod tests {
         assert_eq!(format!("{:?}", Flags128::A), "A");
         assert_eq!(format!("{:?}", Flags128::B), "B");
         assert_eq!(format!("{:?}", Flags128::C), "C");
-        assert_eq!(format!("{:?}", Flags128::ABC), "A | B | C | ABC");
+        assert_eq!(format!("{:?}", Flags128::ABC), "A | B | C");
     }
 
     #[test]
@@ -1952,13 +1890,34 @@ mod tests {
             }
         }
 
+        let count = {
+            #[cfg(any(unix, windows))]
+            {
+                4
+            }
+
+            #[cfg(not(any(unix, windows)))]
+            {
+                3
+            }
+        };
+
         let flags = Flags::all();
-        assert_eq!(flags.iter().count(), 4);
+        assert_eq!(flags.iter().count(), count);
         let mut iter = flags.iter();
-        assert_eq!(iter.next().unwrap(), Flags::ONE);
-        assert_eq!(iter.next().unwrap(), Flags::TWO);
-        assert_eq!(iter.next().unwrap(), Flags::THREE);
-        assert_eq!(iter.next().unwrap(), Flags::FOUR_UNIX);
+        assert_eq!(iter.next().unwrap(), ("ONE", Flags::ONE));
+        assert_eq!(iter.next().unwrap(), ("TWO", Flags::TWO));
+        assert_eq!(iter.next().unwrap(), ("THREE", Flags::THREE));
+
+        #[cfg(unix)]
+        {
+            assert_eq!(iter.next().unwrap(), ("FOUR_UNIX", Flags::FOUR_UNIX));
+        }
+        #[cfg(windows)]
+        {
+            assert_eq!(iter.next().unwrap(), ("FOUR_WIN", Flags::FOUR_WIN));
+        }
+
         assert_eq!(iter.next(), None);
 
         let flags = Flags::empty();
@@ -1967,8 +1926,8 @@ mod tests {
         let flags = Flags::ONE | Flags::THREE;
         assert_eq!(flags.iter().count(), 2);
         let mut iter = flags.iter();
-        assert_eq!(iter.next().unwrap(), Flags::ONE);
-        assert_eq!(iter.next().unwrap(), Flags::THREE);
+        assert_eq!(iter.next().unwrap(), ("ONE", Flags::ONE));
+        assert_eq!(iter.next().unwrap(), ("THREE", Flags::THREE));
         assert_eq!(iter.next(), None);
     }
 }


Test patch:
diff --git a/tests/compile-fail/.gitignore b/tests/compile-fail/.gitignore
deleted file mode 100644
index 4dd9abc..0000000
--- a/tests/compile-fail/.gitignore
+++ /dev/null
@@ -1,1 +0,0 @@
-*.stderr
diff --git a/tests/compile-fail/cfg/multi.stderr b/tests/compile-fail/cfg/multi.stderr
new file mode 100644
index 0000000..be9ba21
--- /dev/null
+++ b/tests/compile-fail/cfg/multi.stderr
@@ -0,0 +1,17 @@
+error[E0428]: the name `FOO` is defined multiple times
+  --> tests/compile-fail/cfg/multi.rs:6:1
+   |
+6  | / bitflags! {
+7  | |     pub struct Flags: u32 {
+8  | |         #[cfg(target_os = "linux")]
+9  | |         const FOO = 1;
+...  |
+12 | |     }
+13 | | }
+   | | ^
+   | | |
+   | |_`FOO` redefined here
+   |   previous definition of the value `FOO` here
+   |
+   = note: `FOO` must be defined only once in the value namespace of this trait
+   = note: this error originates in the macro `__impl_all_bitflags` (in Nightly builds, run with -Z macro-backtrace for more info)
diff --git a/tests/compile-fail/cfg/multi.stderr.beta b/tests/compile-fail/cfg/multi.stderr.beta
deleted file mode 100644
index 7596054..0000000
--- a/tests/compile-fail/cfg/multi.stderr.beta
+++ /dev/null
@@ -1,35 +0,0 @@
-error[E0428]: the name `FOO` is defined multiple times
-  --> $DIR/multi.rs:6:1
-   |
-6  | / bitflags! {
-7  | |     pub struct Flags: u32 {
-8  | |         #[cfg(target_os = "linux")]
-9  | |         const FOO = 1;
-...  |
-12 | |     }
-13 | | }
-   | | ^
-   | | |
-   | |_`FOO` redefined here
-   |   previous definition of the value `FOO` here
-   |
-   = note: `FOO` must be defined only once in the value namespace of this trait
-   = note: this error originates in the macro `__impl_bitflags` (in Nightly builds, run with -Z macro-backtrace for more info)
-
-error[E0428]: the name `FOO` is defined multiple times
-  --> $DIR/multi.rs:6:1
-   |
-6  | / bitflags! {
-7  | |     pub struct Flags: u32 {
-8  | |         #[cfg(target_os = "linux")]
-9  | |         const FOO = 1;
-...  |
-12 | |     }
-13 | | }
-   | | ^
-   | | |
-   | |_`FOO` redefined here
-   |   previous definition of the value `FOO` here
-   |
-   = note: `FOO` must be defined only once in the value namespace of this trait
-   = note: this error originates in the macro `__impl_all_bitflags` (in Nightly builds, run with -Z macro-backtrace for more info)
diff --git a/tests/compile-fail/impls/copy.stderr.beta b/tests/compile-fail/impls/copy.stderr
similarity index 100%
rename from tests/compile-fail/impls/copy.stderr.beta
rename to tests/compile-fail/impls/copy.stderr
diff --git a/tests/compile-fail/impls/eq.stderr.beta b/tests/compile-fail/impls/eq.stderr
similarity index 100%
rename from tests/compile-fail/impls/eq.stderr.beta
rename to tests/compile-fail/impls/eq.stderr
diff --git a/tests/compile-fail/non_integer_base/all_defined.stderr.beta b/tests/compile-fail/non_integer_base/all_defined.stderr
similarity index 64%
rename from tests/compile-fail/non_integer_base/all_defined.stderr.beta
rename to tests/compile-fail/non_integer_base/all_defined.stderr
index 0607f23..fb9c286 100644
--- a/tests/compile-fail/non_integer_base/all_defined.stderr.beta
+++ b/tests/compile-fail/non_integer_base/all_defined.stderr
@@ -1,5 +1,5 @@
 error[E0308]: mismatched types
-   --> $DIR/all_defined.rs:115:1
+   --> tests/compile-fail/non_integer_base/all_defined.rs:115:1
     |
 115 | / bitflags! {
 116 | |     struct Flags128: MyInt {
@@ -13,11 +13,11 @@ error[E0308]: mismatched types
     = note: this error originates in the macro `__impl_bitflags` (in Nightly builds, run with -Z macro-backtrace for more info)
 help: try wrapping the expression in `MyInt`
     |
-492 |                 if extra_bits != MyInt(0) {
+458 |                 if extra_bits != MyInt(0) {
     |                                  ++++++ +
 
 error[E0308]: mismatched types
-   --> $DIR/all_defined.rs:115:1
+   --> tests/compile-fail/non_integer_base/all_defined.rs:115:1
     |
 115 | / bitflags! {
 116 | |     struct Flags128: MyInt {
@@ -31,11 +31,11 @@ error[E0308]: mismatched types
     = note: this error originates in the macro `__impl_bitflags` (in Nightly builds, run with -Z macro-backtrace for more info)
 help: try wrapping the expression in `MyInt`
     |
-536 |                 Self { bits: MyInt(0) }
+508 |                 Self { bits: MyInt(0) }
     |                              ++++++ +
 
 error[E0308]: mismatched types
-   --> $DIR/all_defined.rs:115:1
+   --> tests/compile-fail/non_integer_base/all_defined.rs:115:1
     |
 115 | / bitflags! {
 116 | |     struct Flags128: MyInt {
@@ -49,11 +49,11 @@ error[E0308]: mismatched types
     = note: this error originates in the macro `__impl_bitflags` (in Nightly builds, run with -Z macro-backtrace for more info)
 help: try wrapping the expression in `MyInt`
     |
-574 |                 if bits == MyInt(0) {
+546 |                 if bits == MyInt(0) {
     |                            ++++++ +
 
 error[E0277]: no implementation for `{integer} |= MyInt`
-   --> $DIR/all_defined.rs:115:1
+   --> tests/compile-fail/non_integer_base/all_defined.rs:115:1
     |
 115 | / bitflags! {
 116 | |     struct Flags128: MyInt {
@@ -68,7 +68,7 @@ error[E0277]: no implementation for `{integer} |= MyInt`
     = note: this error originates in the macro `__impl_bitflags` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error[E0308]: mismatched types
-   --> $DIR/all_defined.rs:115:1
+   --> tests/compile-fail/non_integer_base/all_defined.rs:115:1
     |
 115 | / bitflags! {
 116 | |     struct Flags128: MyInt {
@@ -82,47 +82,11 @@ error[E0308]: mismatched types
     = note: this error originates in the macro `__impl_bitflags` (in Nightly builds, run with -Z macro-backtrace for more info)
 help: try wrapping the expression in `MyInt`
     |
-589 |                 Self { bits: MyInt(truncated) }
+561 |                 Self { bits: MyInt(truncated) }
     |                              ++++++         +
 
 error[E0308]: mismatched types
-   --> $DIR/all_defined.rs:115:1
-    |
-115 | / bitflags! {
-116 | |     struct Flags128: MyInt {
-117 | |         const A = MyInt(0b0000_0001u8);
-118 | |         const B = MyInt(0b0000_0010u8);
-119 | |         const C = MyInt(0b0000_0100u8);
-120 | |     }
-121 | | }
-    | |_^ expected struct `MyInt`, found integer
-    |
-    = note: this error originates in the macro `__impl_bitflags` (in Nightly builds, run with -Z macro-backtrace for more info)
-help: try wrapping the expression in `MyInt`
-    |
-471 |                                 if Self::$Flag.bits == MyInt(0) && self.bits != 0 {
-    |                                                        ++++++ +
-
-error[E0308]: mismatched types
-   --> $DIR/all_defined.rs:115:1
-    |
-115 | / bitflags! {
-116 | |     struct Flags128: MyInt {
-117 | |         const A = MyInt(0b0000_0001u8);
-118 | |         const B = MyInt(0b0000_0010u8);
-119 | |         const C = MyInt(0b0000_0100u8);
-120 | |     }
-121 | | }
-    | |_^ expected struct `MyInt`, found integer
-    |
-    = note: this error originates in the macro `__impl_bitflags` (in Nightly builds, run with -Z macro-backtrace for more info)
-help: try wrapping the expression in `MyInt`
-    |
-471 |                                 if Self::$Flag.bits == 0 && self.bits != MyInt(0) {
-    |                                                                          ++++++ +
-
-error[E0308]: mismatched types
-   --> $DIR/all_defined.rs:115:1
+   --> tests/compile-fail/non_integer_base/all_defined.rs:115:1
     |
 115 | / bitflags! {
 116 | |     struct Flags128: MyInt {
@@ -136,5 +100,5 @@ error[E0308]: mismatched types
     = note: this error originates in the macro `__impl_all_bitflags` (in Nightly builds, run with -Z macro-backtrace for more info)
 help: try wrapping the expression in `MyInt`
     |
-410 |                 const $Flag: $T = MyInt(0);
+409 |                 const $Flag: $T = MyInt(0);
     |                                   ++++++ +
diff --git a/tests/compile-fail/non_integer_base/all_missing.stderr.beta b/tests/compile-fail/non_integer_base/all_missing.stderr
similarity index 100%
rename from tests/compile-fail/non_integer_base/all_missing.stderr.beta
rename to tests/compile-fail/non_integer_base/all_missing.stderr
diff --git a/tests/compile-fail/trait/custom_impl.stderr.beta b/tests/compile-fail/trait/custom_impl.stderr
similarity index 100%
rename from tests/compile-fail/trait/custom_impl.stderr.beta
rename to tests/compile-fail/trait/custom_impl.stderr
diff --git a/tests/compile-fail/visibility/private_field.stderr.beta b/tests/compile-fail/visibility/private_field.stderr
similarity index 100%
rename from tests/compile-fail/visibility/private_field.stderr.beta
rename to tests/compile-fail/visibility/private_field.stderr
diff --git a/tests/compile-fail/visibility/private_flags.stderr.beta b/tests/compile-fail/visibility/private_flags.stderr
similarity index 100%
rename from tests/compile-fail/visibility/private_flags.stderr.beta
rename to tests/compile-fail/visibility/private_flags.stderr
diff --git a/tests/compile-fail/visibility/pub_const.stderr.beta b/tests/compile-fail/visibility/pub_const.stderr
similarity index 100%
rename from tests/compile-fail/visibility/pub_const.stderr.beta
rename to tests/compile-fail/visibility/pub_const.stderr
diff --git a/tests/compile-pass/no_prelude.rs b/tests/compile-pass/no_prelude.rs
new file mode 100644
index 0000000..c54b7a3
--- /dev/null
+++ b/tests/compile-pass/no_prelude.rs
@@ -0,0 +1,14 @@
+#![no_implicit_prelude]
+
+extern crate bitflags;
+
+bitflags::bitflags! {
+    pub struct Flags: u32 {
+        const A = 0b00000001;
+        const B = 0b00000010;
+        const C = 0b00000100;
+        const ABC = Flags::A.bits | Flags::B.bits | Flags::C.bits;
+    }
+}
+
+fn main() {}
diff --git a/tests/compile.rs b/tests/compile.rs
index f3ee912..7127ace 100644
--- a/tests/compile.rs
+++ b/tests/compile.rs
@@ -1,26 +1,12 @@
-use std::{
-    env,
-    fs,
-    ffi::OsStr,
-    io,
-    path::Path,
-};
-
-use walkdir::WalkDir;
-
-#[test]
+// Compiler messages change frequently enough that we can end up with
+// an impossible build between error messages emitted on various channels.
+// Since https://github.com/dtolnay/trybuild/pull/170 we always need to have a
+// `stderr` file for each test so we can't simply ignore the output on different channels.
+#[rustversion::attr(beta, test)]
+#[allow(dead_code)]
 fn fail() {
-    prepare_stderr_files("tests/compile-fail").unwrap();
-
     let t = trybuild::TestCases::new();
-
     t.compile_fail("tests/compile-fail/**/*.rs");
-
-    // `trybuild` will run its tests on `drop`
-    // We want to get a chance to use its output first
-    drop(t);
-
-    overwrite_stderr_files("tests/compile-fail").unwrap();
 }
 
 #[test]
@@ -28,81 +14,3 @@ fn pass() {
     let t = trybuild::TestCases::new();
     t.pass("tests/compile-pass/**/*.rs");
 }
-
-// Compiler messages may change between versions
-// We don't want to have to track these too closely for `bitflags`, but
-// having some message to check makes sure user-facing errors are sensical.
-// 
-// The approach we use is to run the test on all compilers, but only check stderr
-// output on beta (which is the next stable release). We do this by default ignoring
-// any `.stderr` files in the `compile-fail` directory, and copying `.stderr.beta` files
-// when we happen to be running on a beta compiler.
-fn prepare_stderr_files(path: impl AsRef<Path>) -> io::Result<()> {
-    for entry in WalkDir::new(path) {
-        let entry = entry?;
-
-        if entry.path().extension().and_then(OsStr::to_str) == Some("beta") {
-            let renamed = entry.path().with_extension("");
-
-            // Unconditionally remove a corresponding `.stderr` file for a `.stderr.beta`
-            // file if it exists. On `beta` compilers, we'll recreate it. On other compilers,
-            // we don't want to end up checking it anyways.
-            if renamed.exists() {
-                fs::remove_file(&renamed)?;
-            }
-
-            rename_beta_stderr(entry.path(), renamed)?;
-        }
-    }
-
-    Ok(())
-}
-
-// If we want to overwrite the expected compiler output then rename it
-// to use our `.stderr.beta` convention. Otherwise the renamed file won't
-// actually get picked up on the next run
-fn overwrite_stderr_files(path: impl AsRef<Path>) -> io::Result<()> {
-    if env::var("TRYBUILD").ok().filter(|o| o == "overwrite").is_some() {
-        for entry in WalkDir::new(path) {
-            let entry = entry?;
-    
-            // Look for any `.stderr` files and rename them to `.stderr.beta`
-            // If there's an existing `.beta` file then we want to remove it
-            if entry.path().extension().and_then(OsStr::to_str) == Some("stderr") {
-                let renamed = entry.path().with_extension("stderr.beta");
-
-                if renamed.exists() {
-                    remove_beta_stderr(&renamed)?;
-                }
-    
-                rename_beta_stderr(entry.path(), renamed)?;
-            }
-        }
-    }
-
-    Ok(())
-}
-
-#[rustversion::beta]
-fn remove_beta_stderr(path: impl AsRef<Path>) -> io::Result<()> {
-    fs::remove_file(path)?;
-
-    Ok(())
-}
-
-#[rustversion::not(beta)]
-fn remove_beta_stderr(_: impl AsRef<Path>) -> io::Result<()> {
-    Ok(())
-}
-
-#[rustversion::beta]
-fn rename_beta_stderr(from: impl AsRef<Path>, to: impl AsRef<Path>) -> io::Result<()> {
-    fs::copy(from, to)?;
-
-    Ok(())
-}
-
-#[rustversion::not(beta)]
-fn rename_beta_stderr(_: impl AsRef<Path>, _: impl AsRef<Path>) -> io::Result<()> {
-    Ok(())
-}