From 2a899dc1cfe37270cf976b54a2953133faafa0ae Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Thu, 7 Jul 2022 10:46:22 +0000 Subject: [PATCH 01/29] `UnsafeCell` now has no niches, ever. --- compiler/rustc_attr/src/builtin.rs | 8 +- .../rustc_const_eval/src/interpret/intern.rs | 2 +- .../src/interpret/validity.rs | 2 +- .../src/transform/check_consts/qualifs.rs | 4 +- compiler/rustc_feature/src/active.rs | 3 - compiler/rustc_lint/src/types.rs | 2 +- compiler/rustc_middle/src/ty/adt.rs | 11 + compiler/rustc_middle/src/ty/layout.rs | 48 +-- compiler/rustc_middle/src/ty/mod.rs | 10 +- compiler/rustc_passes/src/check_attr.rs | 21 +- compiler/rustc_span/src/symbol.rs | 2 - library/core/src/cell.rs | 1 - library/core/src/lib.rs | 1 - src/test/ui/layout/unsafe-cell-hides-niche.rs | 5 +- src/test/ui/lint/clashing-extern-fn.rs | 4 +- src/test/ui/lint/clashing-extern-fn.stderr | 40 +-- src/test/ui/repr/feature-gate-no-niche.rs | 20 -- src/test/ui/repr/feature-gate-no-niche.stderr | 35 -- .../repr-no-niche-inapplicable-to-unions.rs | 14 - ...epr-no-niche-inapplicable-to-unions.stderr | 19 - src/test/ui/repr/repr-no-niche.rs | 327 ------------------ .../clippy/clippy_lints/src/non_copy_const.rs | 2 +- 22 files changed, 71 insertions(+), 510 deletions(-) delete mode 100644 src/test/ui/repr/feature-gate-no-niche.rs delete mode 100644 src/test/ui/repr/feature-gate-no-niche.stderr delete mode 100644 src/test/ui/repr/repr-no-niche-inapplicable-to-unions.rs delete mode 100644 src/test/ui/repr/repr-no-niche-inapplicable-to-unions.stderr delete mode 100644 src/test/ui/repr/repr-no-niche.rs diff --git a/compiler/rustc_attr/src/builtin.rs b/compiler/rustc_attr/src/builtin.rs index ce7c0eb72cd24..6673d75d99df0 100644 --- a/compiler/rustc_attr/src/builtin.rs +++ b/compiler/rustc_attr/src/builtin.rs @@ -856,7 +856,6 @@ pub enum ReprAttr { ReprSimd, ReprTransparent, ReprAlign(u32), - ReprNoNiche, } #[derive(Eq, PartialEq, Debug, Copy, Clone)] @@ -904,7 +903,6 @@ pub fn parse_repr_attr(sess: &Session, attr: &Attribute) -> Vec { sym::packed => Some(ReprPacked(1)), sym::simd => Some(ReprSimd), sym::transparent => Some(ReprTransparent), - sym::no_niche => Some(ReprNoNiche), sym::align => { let mut err = struct_span_err!( diagnostic, @@ -943,7 +941,7 @@ pub fn parse_repr_attr(sess: &Session, attr: &Attribute) -> Vec { Ok(literal) => acc.push(ReprPacked(literal)), Err(message) => literal_error = Some(message), }; - } else if matches!(name, sym::C | sym::simd | sym::transparent | sym::no_niche) + } else if matches!(name, sym::C | sym::simd | sym::transparent) || int_type_of_word(name).is_some() { recognised = true; @@ -1001,7 +999,7 @@ pub fn parse_repr_attr(sess: &Session, attr: &Attribute) -> Vec { } else { if matches!( meta_item.name_or_empty(), - sym::C | sym::simd | sym::transparent | sym::no_niche + sym::C | sym::simd | sym::transparent ) || int_type_of_word(meta_item.name_or_empty()).is_some() { recognised = true; @@ -1039,7 +1037,7 @@ pub fn parse_repr_attr(sess: &Session, attr: &Attribute) -> Vec { .emit(); } else if matches!( meta_item.name_or_empty(), - sym::C | sym::simd | sym::transparent | sym::no_niche + sym::C | sym::simd | sym::transparent ) || int_type_of_word(meta_item.name_or_empty()).is_some() { recognised = true; diff --git a/compiler/rustc_const_eval/src/interpret/intern.rs b/compiler/rustc_const_eval/src/interpret/intern.rs index 9dfdafcb38e0b..7616e7a63d107 100644 --- a/compiler/rustc_const_eval/src/interpret/intern.rs +++ b/compiler/rustc_const_eval/src/interpret/intern.rs @@ -217,7 +217,7 @@ impl<'rt, 'mir, 'tcx: 'mir, M: CompileTimeMachine<'mir, 'tcx, const_eval::Memory } if let Some(def) = mplace.layout.ty.ty_adt_def() { - if Some(def.did()) == self.ecx.tcx.lang_items().unsafe_cell_type() { + if def.is_unsafe_cell() { // We are crossing over an `UnsafeCell`, we can mutate again. This means that // References we encounter inside here are interned as pointing to mutable // allocations. diff --git a/compiler/rustc_const_eval/src/interpret/validity.rs b/compiler/rustc_const_eval/src/interpret/validity.rs index 0bf78446e37fa..48ca5913fabbd 100644 --- a/compiler/rustc_const_eval/src/interpret/validity.rs +++ b/compiler/rustc_const_eval/src/interpret/validity.rs @@ -821,7 +821,7 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValueVisitor<'mir, 'tcx, M> // Special check preventing `UnsafeCell` in the inner part of constants if let Some(def) = op.layout.ty.ty_adt_def() { if matches!(self.ctfe_mode, Some(CtfeValidationMode::Const { inner: true, .. })) - && Some(def.did()) == self.ecx.tcx.lang_items().unsafe_cell_type() + && def.is_unsafe_cell() { throw_validation_failure!(self.path, { "`UnsafeCell` in a `const`" }); } diff --git a/compiler/rustc_const_eval/src/transform/check_consts/qualifs.rs b/compiler/rustc_const_eval/src/transform/check_consts/qualifs.rs index 6e5a0c813ac20..770286599d25f 100644 --- a/compiler/rustc_const_eval/src/transform/check_consts/qualifs.rs +++ b/compiler/rustc_const_eval/src/transform/check_consts/qualifs.rs @@ -96,13 +96,13 @@ impl Qualif for HasMutInterior { } fn in_adt_inherently<'tcx>( - cx: &ConstCx<'_, 'tcx>, + _cx: &ConstCx<'_, 'tcx>, adt: AdtDef<'tcx>, _: SubstsRef<'tcx>, ) -> bool { // Exactly one type, `UnsafeCell`, has the `HasMutInterior` qualif inherently. // It arises structurally for all other types. - Some(adt.did()) == cx.tcx.lang_items().unsafe_cell_type() + adt.is_unsafe_cell() } } diff --git a/compiler/rustc_feature/src/active.rs b/compiler/rustc_feature/src/active.rs index b54f0ef361a8d..117bdad971a20 100644 --- a/compiler/rustc_feature/src/active.rs +++ b/compiler/rustc_feature/src/active.rs @@ -156,9 +156,6 @@ declare_features! ( (active, intrinsics, "1.0.0", None, None), /// Allows using `#[lang = ".."]` attribute for linking items to special compiler logic. (active, lang_items, "1.0.0", None, None), - /// Allows `#[repr(no_niche)]` (an implementation detail of `rustc`, - /// it is not on path for eventual stabilization). - (active, no_niche, "1.42.0", None, None), /// Allows using `#[omit_gdb_pretty_printer_section]`. (active, omit_gdb_pretty_printer_section, "1.5.0", None, None), /// Allows using `#[prelude_import]` on glob `use` items. diff --git a/compiler/rustc_lint/src/types.rs b/compiler/rustc_lint/src/types.rs index be4843c7ff153..4ed9d9b27b297 100644 --- a/compiler/rustc_lint/src/types.rs +++ b/compiler/rustc_lint/src/types.rs @@ -705,7 +705,7 @@ fn ty_is_known_nonnull<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>, mode: CItemKi // Types with a `#[repr(no_niche)]` attribute have their niche hidden. // The attribute is used by the UnsafeCell for example (the only use so far). - if def.repr().hide_niche() { + if def.is_unsafe_cell() { return false; } diff --git a/compiler/rustc_middle/src/ty/adt.rs b/compiler/rustc_middle/src/ty/adt.rs index bf7cb610a9097..9972199c62e04 100644 --- a/compiler/rustc_middle/src/ty/adt.rs +++ b/compiler/rustc_middle/src/ty/adt.rs @@ -52,6 +52,8 @@ bitflags! { /// Indicates whether the variant list of this ADT is `#[non_exhaustive]`. /// (i.e., this flag is never set unless this ADT is an enum). const IS_VARIANT_LIST_NON_EXHAUSTIVE = 1 << 8; + /// Indicates whether the type is `UnsafeCell`. + const IS_UNSAFE_CELL = 1 << 9; } } @@ -242,6 +244,9 @@ impl AdtDefData { if Some(did) == tcx.lang_items().manually_drop() { flags |= AdtFlags::IS_MANUALLY_DROP; } + if Some(did) == tcx.lang_items().unsafe_cell_type() { + flags |= AdtFlags::IS_UNSAFE_CELL; + } AdtDefData { did, variants, flags, repr } } @@ -328,6 +333,12 @@ impl<'tcx> AdtDef<'tcx> { self.flags().contains(AdtFlags::IS_BOX) } + /// Returns `true` if this is UnsafeCell. + #[inline] + pub fn is_unsafe_cell(self) -> bool { + self.flags().contains(AdtFlags::IS_UNSAFE_CELL) + } + /// Returns `true` if this is `ManuallyDrop`. #[inline] pub fn is_manually_drop(self) -> bool { diff --git a/compiler/rustc_middle/src/ty/layout.rs b/compiler/rustc_middle/src/ty/layout.rs index f87b6e4212d29..cef8a1dba7f8d 100644 --- a/compiler/rustc_middle/src/ty/layout.rs +++ b/compiler/rustc_middle/src/ty/layout.rs @@ -542,14 +542,12 @@ impl<'tcx> LayoutCx<'tcx, TyCtxt<'tcx>> { debug!("univariant offset: {:?} field: {:#?}", offset, field); offsets[i as usize] = offset; - if !repr.hide_niche() { - if let Some(mut niche) = field.largest_niche { - let available = niche.available(dl); - if available > largest_niche_available { - largest_niche_available = available; - niche.offset += offset; - largest_niche = Some(niche); - } + if let Some(mut niche) = field.largest_niche { + let available = niche.available(dl); + if available > largest_niche_available { + largest_niche_available = available; + niche.offset += offset; + largest_niche = Some(niche); } } @@ -1104,23 +1102,29 @@ impl<'tcx> LayoutCx<'tcx, TyCtxt<'tcx>> { assert!(valid_range.end >= end); valid_range.end = end; } - - // Update `largest_niche` if we have introduced a larger niche. - let niche = if def.repr().hide_niche() { - None + if def.is_unsafe_cell() { + match scalar { + Scalar::Initialized { value, valid_range } => { + *valid_range = WrappingRange::full(value.size(dl)) + } + // Already doesn't have any niches + Scalar::Union { .. } => {} + } + st.largest_niche = None; } else { - Niche::from_scalar(dl, Size::ZERO, *scalar) - }; - if let Some(niche) = niche { - match st.largest_niche { - Some(largest_niche) => { - // Replace the existing niche even if they're equal, - // because this one is at a lower offset. - if largest_niche.available(dl) <= niche.available(dl) { - st.largest_niche = Some(niche); + // Update `largest_niche` if we have introduced a larger niche. + let niche = Niche::from_scalar(dl, Size::ZERO, *scalar); + if let Some(niche) = niche { + match st.largest_niche { + Some(largest_niche) => { + // Replace the existing niche even if they're equal, + // because this one is at a lower offset. + if largest_niche.available(dl) <= niche.available(dl) { + st.largest_niche = Some(niche); + } } + None => st.largest_niche = Some(niche), } - None => st.largest_niche = Some(niche), } } } diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs index 3a795af2121d0..058cf1a4183df 100644 --- a/compiler/rustc_middle/src/ty/mod.rs +++ b/compiler/rustc_middle/src/ty/mod.rs @@ -1719,11 +1719,9 @@ bitflags! { const IS_TRANSPARENT = 1 << 2; // Internal only for now. If true, don't reorder fields. const IS_LINEAR = 1 << 3; - // If true, don't expose any niche to type's context. - const HIDE_NICHE = 1 << 4; // If true, the type's layout can be randomized using // the seed stored in `ReprOptions.layout_seed` - const RANDOMIZE_LAYOUT = 1 << 5; + const RANDOMIZE_LAYOUT = 1 << 4; // Any of these flags being set prevent field reordering optimisation. const IS_UNOPTIMISABLE = ReprFlags::IS_C.bits | ReprFlags::IS_SIMD.bits @@ -1780,7 +1778,6 @@ impl ReprOptions { ReprFlags::empty() } attr::ReprTransparent => ReprFlags::IS_TRANSPARENT, - attr::ReprNoNiche => ReprFlags::HIDE_NICHE, attr::ReprSimd => ReprFlags::IS_SIMD, attr::ReprInt(i) => { size = Some(i); @@ -1833,11 +1830,6 @@ impl ReprOptions { self.flags.contains(ReprFlags::IS_LINEAR) } - #[inline] - pub fn hide_niche(&self) -> bool { - self.flags.contains(ReprFlags::HIDE_NICHE) - } - /// Returns the discriminant type, given these `repr` options. /// This must only be called on enums! pub fn discr_type(&self) -> attr::IntType { diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs index 8c123c052e5ac..cd5357d796d9a 100644 --- a/compiler/rustc_passes/src/check_attr.rs +++ b/compiler/rustc_passes/src/check_attr.rs @@ -1808,21 +1808,6 @@ impl CheckAttrVisitor<'_> { _ => ("a", "struct, enum, or union"), } } - sym::no_niche => { - if !self.tcx.features().enabled(sym::no_niche) { - feature_err( - &self.tcx.sess.parse_sess, - sym::no_niche, - hint.span(), - "the attribute `repr(no_niche)` is currently unstable", - ) - .emit(); - } - match target { - Target::Struct | Target::Enum => continue, - _ => ("a", "struct or enum"), - } - } sym::i8 | sym::u8 | sym::i16 @@ -1870,10 +1855,8 @@ impl CheckAttrVisitor<'_> { // This is not ideal, but tracking precisely which ones are at fault is a huge hassle. let hint_spans = hints.iter().map(|hint| hint.span()); - // Error on repr(transparent, ). - let non_no_niche = |hint: &&NestedMetaItem| hint.name_or_empty() != sym::no_niche; - let non_no_niche_count = hints.iter().filter(non_no_niche).count(); - if is_transparent && non_no_niche_count > 1 { + // Error on repr(transparent, ). + if is_transparent && hints.len() > 1 { let hint_spans: Vec<_> = hint_spans.clone().collect(); struct_span_err!( self.tcx.sess, diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index 65a2a18e02f8f..43312105fd6b0 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -979,7 +979,6 @@ symbols! { no_link, no_main, no_mangle, - no_niche, no_sanitize, no_stack_check, no_start, @@ -1152,7 +1151,6 @@ symbols! { repr128, repr_align, repr_align_enum, - repr_no_niche, repr_packed, repr_simd, repr_transparent, diff --git a/library/core/src/cell.rs b/library/core/src/cell.rs index 63c83ddb6f7cf..8a37fadc56f4c 100644 --- a/library/core/src/cell.rs +++ b/library/core/src/cell.rs @@ -1856,7 +1856,6 @@ impl fmt::Display for RefMut<'_, T> { #[lang = "unsafe_cell"] #[stable(feature = "rust1", since = "1.0.0")] #[repr(transparent)] -#[repr(no_niche)] // rust-lang/rust#68303. pub struct UnsafeCell { value: T, } diff --git a/library/core/src/lib.rs b/library/core/src/lib.rs index 093c7d298734a..19775e7acda2f 100644 --- a/library/core/src/lib.rs +++ b/library/core/src/lib.rs @@ -191,7 +191,6 @@ #![feature(never_type)] #![feature(no_core)] #![feature(no_coverage)] // rust-lang/rust#84605 -#![feature(no_niche)] // rust-lang/rust#68303 #![feature(platform_intrinsics)] #![feature(prelude_import)] #![feature(repr_simd)] diff --git a/src/test/ui/layout/unsafe-cell-hides-niche.rs b/src/test/ui/layout/unsafe-cell-hides-niche.rs index 4ca3f7a1aad94..eb65756a5f643 100644 --- a/src/test/ui/layout/unsafe-cell-hides-niche.rs +++ b/src/test/ui/layout/unsafe-cell-hides-niche.rs @@ -5,8 +5,6 @@ // run-pass -#![feature(no_niche)] - use std::cell::UnsafeCell; use std::mem::size_of; use std::num::NonZeroU32 as N32; @@ -16,8 +14,7 @@ struct Wrapper(T); #[repr(transparent)] struct Transparent(T); -#[repr(no_niche)] -struct NoNiche(T); +struct NoNiche(UnsafeCell); fn main() { assert_eq!(size_of::>>(), 8); diff --git a/src/test/ui/lint/clashing-extern-fn.rs b/src/test/ui/lint/clashing-extern-fn.rs index 2ce4dd56eab0d..809e0602671fe 100644 --- a/src/test/ui/lint/clashing-extern-fn.rs +++ b/src/test/ui/lint/clashing-extern-fn.rs @@ -1,7 +1,6 @@ // check-pass // aux-build:external_extern_fn.rs #![crate_type = "lib"] -#![feature(no_niche)] #![warn(clashing_extern_declarations)] mod redeclared_different_signature { @@ -400,9 +399,8 @@ mod hidden_niche { #[repr(transparent)] struct Transparent { x: NonZeroUsize } - #[repr(no_niche)] #[repr(transparent)] - struct TransparentNoNiche { y: NonZeroUsize } + struct TransparentNoNiche { y: UnsafeCell } extern "C" { fn hidden_niche_transparent() -> Option; diff --git a/src/test/ui/lint/clashing-extern-fn.stderr b/src/test/ui/lint/clashing-extern-fn.stderr index a856de322c8ca..4607f68499322 100644 --- a/src/test/ui/lint/clashing-extern-fn.stderr +++ b/src/test/ui/lint/clashing-extern-fn.stderr @@ -1,5 +1,5 @@ warning: `clash` redeclared with a different signature - --> $DIR/clashing-extern-fn.rs:15:13 + --> $DIR/clashing-extern-fn.rs:14:13 | LL | fn clash(x: u8); | ---------------- `clash` previously declared here @@ -8,7 +8,7 @@ LL | fn clash(x: u64); | ^^^^^^^^^^^^^^^^^ this signature doesn't match the previous declaration | note: the lint level is defined here - --> $DIR/clashing-extern-fn.rs:5:9 + --> $DIR/clashing-extern-fn.rs:4:9 | LL | #![warn(clashing_extern_declarations)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -16,7 +16,7 @@ LL | #![warn(clashing_extern_declarations)] found `unsafe extern "C" fn(u64)` warning: `extern_link_name` redeclared with a different signature - --> $DIR/clashing-extern-fn.rs:53:9 + --> $DIR/clashing-extern-fn.rs:52:9 | LL | / #[link_name = "extern_link_name"] LL | | fn some_new_name(x: i16); @@ -29,7 +29,7 @@ LL | fn extern_link_name(x: u32); found `unsafe extern "C" fn(u32)` warning: `some_other_extern_link_name` redeclares `some_other_new_name` with a different signature - --> $DIR/clashing-extern-fn.rs:56:9 + --> $DIR/clashing-extern-fn.rs:55:9 | LL | fn some_other_new_name(x: i16); | ------------------------------- `some_other_new_name` previously declared here @@ -43,7 +43,7 @@ LL | | fn some_other_extern_link_name(x: u32); found `unsafe extern "C" fn(u32)` warning: `other_both_names_different` redeclares `link_name_same` with a different signature - --> $DIR/clashing-extern-fn.rs:60:9 + --> $DIR/clashing-extern-fn.rs:59:9 | LL | / #[link_name = "link_name_same"] LL | | fn both_names_different(x: i16); @@ -58,7 +58,7 @@ LL | | fn other_both_names_different(x: u32); found `unsafe extern "C" fn(u32)` warning: `different_mod` redeclared with a different signature - --> $DIR/clashing-extern-fn.rs:73:9 + --> $DIR/clashing-extern-fn.rs:72:9 | LL | fn different_mod(x: u8); | ------------------------ `different_mod` previously declared here @@ -70,7 +70,7 @@ LL | fn different_mod(x: u64); found `unsafe extern "C" fn(u64)` warning: `variadic_decl` redeclared with a different signature - --> $DIR/clashing-extern-fn.rs:83:9 + --> $DIR/clashing-extern-fn.rs:82:9 | LL | fn variadic_decl(x: u8, ...); | ----------------------------- `variadic_decl` previously declared here @@ -82,7 +82,7 @@ LL | fn variadic_decl(x: u8); found `unsafe extern "C" fn(u8)` warning: `weigh_banana` redeclared with a different signature - --> $DIR/clashing-extern-fn.rs:143:13 + --> $DIR/clashing-extern-fn.rs:142:13 | LL | fn weigh_banana(count: *const Banana) -> u64; | --------------------------------------------- `weigh_banana` previously declared here @@ -94,7 +94,7 @@ LL | fn weigh_banana(count: *const Banana) -> u64; found `unsafe extern "C" fn(*const three::Banana) -> u64` warning: `draw_point` redeclared with a different signature - --> $DIR/clashing-extern-fn.rs:172:13 + --> $DIR/clashing-extern-fn.rs:171:13 | LL | fn draw_point(p: Point); | ------------------------ `draw_point` previously declared here @@ -106,7 +106,7 @@ LL | fn draw_point(p: Point); found `unsafe extern "C" fn(sameish_members::b::Point)` warning: `origin` redeclared with a different signature - --> $DIR/clashing-extern-fn.rs:198:13 + --> $DIR/clashing-extern-fn.rs:197:13 | LL | fn origin() -> Point3; | ---------------------- `origin` previously declared here @@ -118,7 +118,7 @@ LL | fn origin() -> Point3; found `unsafe extern "C" fn() -> same_sized_members_clash::b::Point3` warning: `transparent_incorrect` redeclared with a different signature - --> $DIR/clashing-extern-fn.rs:221:13 + --> $DIR/clashing-extern-fn.rs:220:13 | LL | fn transparent_incorrect() -> T; | -------------------------------- `transparent_incorrect` previously declared here @@ -130,7 +130,7 @@ LL | fn transparent_incorrect() -> isize; found `unsafe extern "C" fn() -> isize` warning: `missing_return_type` redeclared with a different signature - --> $DIR/clashing-extern-fn.rs:239:13 + --> $DIR/clashing-extern-fn.rs:238:13 | LL | fn missing_return_type() -> usize; | ---------------------------------- `missing_return_type` previously declared here @@ -142,7 +142,7 @@ LL | fn missing_return_type(); found `unsafe extern "C" fn()` warning: `non_zero_usize` redeclared with a different signature - --> $DIR/clashing-extern-fn.rs:257:13 + --> $DIR/clashing-extern-fn.rs:256:13 | LL | fn non_zero_usize() -> core::num::NonZeroUsize; | ----------------------------------------------- `non_zero_usize` previously declared here @@ -154,7 +154,7 @@ LL | fn non_zero_usize() -> usize; found `unsafe extern "C" fn() -> usize` warning: `non_null_ptr` redeclared with a different signature - --> $DIR/clashing-extern-fn.rs:259:13 + --> $DIR/clashing-extern-fn.rs:258:13 | LL | fn non_null_ptr() -> core::ptr::NonNull; | ----------------------------------------------- `non_null_ptr` previously declared here @@ -166,7 +166,7 @@ LL | fn non_null_ptr() -> *const usize; found `unsafe extern "C" fn() -> *const usize` warning: `option_non_zero_usize_incorrect` redeclared with a different signature - --> $DIR/clashing-extern-fn.rs:357:13 + --> $DIR/clashing-extern-fn.rs:356:13 | LL | fn option_non_zero_usize_incorrect() -> usize; | ---------------------------------------------- `option_non_zero_usize_incorrect` previously declared here @@ -178,7 +178,7 @@ LL | fn option_non_zero_usize_incorrect() -> isize; found `unsafe extern "C" fn() -> isize` warning: `option_non_null_ptr_incorrect` redeclared with a different signature - --> $DIR/clashing-extern-fn.rs:359:13 + --> $DIR/clashing-extern-fn.rs:358:13 | LL | fn option_non_null_ptr_incorrect() -> *const usize; | --------------------------------------------------- `option_non_null_ptr_incorrect` previously declared here @@ -190,7 +190,7 @@ LL | fn option_non_null_ptr_incorrect() -> *const isize; found `unsafe extern "C" fn() -> *const isize` warning: `hidden_niche_transparent_no_niche` redeclared with a different signature - --> $DIR/clashing-extern-fn.rs:410:13 + --> $DIR/clashing-extern-fn.rs:408:13 | LL | fn hidden_niche_transparent_no_niche() -> usize; | ------------------------------------------------ `hidden_niche_transparent_no_niche` previously declared here @@ -202,7 +202,7 @@ LL | fn hidden_niche_transparent_no_niche() -> Option Option` warning: `hidden_niche_unsafe_cell` redeclared with a different signature - --> $DIR/clashing-extern-fn.rs:414:13 + --> $DIR/clashing-extern-fn.rs:412:13 | LL | fn hidden_niche_unsafe_cell() -> usize; | --------------------------------------- `hidden_niche_unsafe_cell` previously declared here @@ -214,7 +214,7 @@ LL | fn hidden_niche_unsafe_cell() -> Option Option>` warning: `extern` block uses type `Option`, which is not FFI-safe - --> $DIR/clashing-extern-fn.rs:410:55 + --> $DIR/clashing-extern-fn.rs:408:55 | LL | fn hidden_niche_transparent_no_niche() -> Option; | ^^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe @@ -224,7 +224,7 @@ LL | fn hidden_niche_transparent_no_niche() -> Option>`, which is not FFI-safe - --> $DIR/clashing-extern-fn.rs:414:46 + --> $DIR/clashing-extern-fn.rs:412:46 | LL | fn hidden_niche_unsafe_cell() -> Option>; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe diff --git a/src/test/ui/repr/feature-gate-no-niche.rs b/src/test/ui/repr/feature-gate-no-niche.rs deleted file mode 100644 index 8872ee7119e4a..0000000000000 --- a/src/test/ui/repr/feature-gate-no-niche.rs +++ /dev/null @@ -1,20 +0,0 @@ -use std::num::NonZeroU8 as N8; -use std::num::NonZeroU16 as N16; - -#[repr(no_niche)] -pub struct Cloaked(N16); -//~^^ ERROR the attribute `repr(no_niche)` is currently unstable [E0658] - -#[repr(transparent, no_niche)] -pub struct Shadowy(N16); -//~^^ ERROR the attribute `repr(no_niche)` is currently unstable [E0658] - -#[repr(no_niche)] -pub enum Cloaked1 { _A(N16), } -//~^^ ERROR the attribute `repr(no_niche)` is currently unstable [E0658] - -#[repr(no_niche)] -pub enum Cloaked2 { _A(N16), _B(u8, N8) } -//~^^ ERROR the attribute `repr(no_niche)` is currently unstable [E0658] - -fn main() { } diff --git a/src/test/ui/repr/feature-gate-no-niche.stderr b/src/test/ui/repr/feature-gate-no-niche.stderr deleted file mode 100644 index 34fd417cc99a2..0000000000000 --- a/src/test/ui/repr/feature-gate-no-niche.stderr +++ /dev/null @@ -1,35 +0,0 @@ -error[E0658]: the attribute `repr(no_niche)` is currently unstable - --> $DIR/feature-gate-no-niche.rs:4:8 - | -LL | #[repr(no_niche)] - | ^^^^^^^^ - | - = help: add `#![feature(no_niche)]` to the crate attributes to enable - -error[E0658]: the attribute `repr(no_niche)` is currently unstable - --> $DIR/feature-gate-no-niche.rs:8:21 - | -LL | #[repr(transparent, no_niche)] - | ^^^^^^^^ - | - = help: add `#![feature(no_niche)]` to the crate attributes to enable - -error[E0658]: the attribute `repr(no_niche)` is currently unstable - --> $DIR/feature-gate-no-niche.rs:12:8 - | -LL | #[repr(no_niche)] - | ^^^^^^^^ - | - = help: add `#![feature(no_niche)]` to the crate attributes to enable - -error[E0658]: the attribute `repr(no_niche)` is currently unstable - --> $DIR/feature-gate-no-niche.rs:16:8 - | -LL | #[repr(no_niche)] - | ^^^^^^^^ - | - = help: add `#![feature(no_niche)]` to the crate attributes to enable - -error: aborting due to 4 previous errors - -For more information about this error, try `rustc --explain E0658`. diff --git a/src/test/ui/repr/repr-no-niche-inapplicable-to-unions.rs b/src/test/ui/repr/repr-no-niche-inapplicable-to-unions.rs deleted file mode 100644 index 870eda89c20d7..0000000000000 --- a/src/test/ui/repr/repr-no-niche-inapplicable-to-unions.rs +++ /dev/null @@ -1,14 +0,0 @@ -#![feature(no_niche)] - -use std::num::NonZeroU8 as N8; -use std::num::NonZeroU16 as N16; - -#[repr(no_niche)] -pub union Cloaked1 { _A: N16 } -//~^^ ERROR attribute should be applied to a struct or enum [E0517] - -#[repr(no_niche)] -pub union Cloaked2 { _A: N16, _B: (u8, N8) } -//~^^ ERROR attribute should be applied to a struct or enum [E0517] - -fn main() { } diff --git a/src/test/ui/repr/repr-no-niche-inapplicable-to-unions.stderr b/src/test/ui/repr/repr-no-niche-inapplicable-to-unions.stderr deleted file mode 100644 index 9af929d409473..0000000000000 --- a/src/test/ui/repr/repr-no-niche-inapplicable-to-unions.stderr +++ /dev/null @@ -1,19 +0,0 @@ -error[E0517]: attribute should be applied to a struct or enum - --> $DIR/repr-no-niche-inapplicable-to-unions.rs:6:8 - | -LL | #[repr(no_niche)] - | ^^^^^^^^ -LL | pub union Cloaked1 { _A: N16 } - | ------------------------------ not a struct or enum - -error[E0517]: attribute should be applied to a struct or enum - --> $DIR/repr-no-niche-inapplicable-to-unions.rs:10:8 - | -LL | #[repr(no_niche)] - | ^^^^^^^^ -LL | pub union Cloaked2 { _A: N16, _B: (u8, N8) } - | -------------------------------------------- not a struct or enum - -error: aborting due to 2 previous errors - -For more information about this error, try `rustc --explain E0517`. diff --git a/src/test/ui/repr/repr-no-niche.rs b/src/test/ui/repr/repr-no-niche.rs deleted file mode 100644 index 2e6064aeb0074..0000000000000 --- a/src/test/ui/repr/repr-no-niche.rs +++ /dev/null @@ -1,327 +0,0 @@ -// run-pass - -// This file tests repr(no_niche), which causes an struct/enum to hide -// any niche space that may exist in its internal state from the -// context it appears in. - -// Here are the axes this test is seeking to cover: -// -// repr annotation: -// visible: (); cloaked: (no_niche); transparent: (transparent); shadowy: (transparent, no_niche) -// -// enum vs struct -// -// niche-type via type-parameter vs inline declaration - -#![feature(decl_macro)] -#![feature(no_niche)] - -use std::mem::size_of; -use std::num::{NonZeroU8, NonZeroU16}; - -mod struct_inline { - use std::num::NonZeroU16 as N16; - - #[derive(Debug)] pub struct Visible(N16); - - #[repr(no_niche)] - #[derive(Debug)] pub struct Cloaked(N16); - - #[repr(transparent)] - #[derive(Debug)] pub struct Transparent(N16); - - #[repr(transparent, no_niche)] - #[derive(Debug)] pub struct Shadowy(N16); -} - -mod struct_param { - #[derive(Debug)] pub struct Visible(T); - - #[repr(no_niche)] - #[derive(Debug)] pub struct Cloaked(T); - - #[repr(transparent)] - #[derive(Debug)] pub struct Transparent(T); - - #[repr(transparent, no_niche)] - #[derive(Debug)] pub struct Shadowy(T); -} - -mod enum_inline { - use crate::two_fifty_six_variant_enum; - use std::num::{NonZeroU8 as N8, NonZeroU16 as N16}; - - #[derive(Debug)] pub enum Visible1 { _A(N16), } - - #[repr(no_niche)] - #[derive(Debug)] pub enum Cloaked1 { _A(N16), } - - // (N.B.: transparent enums must be univariant) - #[repr(transparent)] - #[derive(Debug)] pub enum Transparent { _A(N16), } - - #[repr(transparent, no_niche)] - #[derive(Debug)] pub enum Shadowy { _A(N16), } - - // including multivariant enums for completeness. Payload and - // number of variants (i.e. discriminant size) have been chosen so - // that layout including discriminant is 4 bytes, with no space in - // padding to hide another discrimnant from the surrounding - // context. - // - // (Note that multivariant enums cannot usefully expose a niche in - // general; this test is relying on that.) - two_fifty_six_variant_enum!(Visible2, N8); - - two_fifty_six_variant_enum!(#[repr(no_niche)] Cloaked2, N8); -} - -mod enum_param { - use super::two_fifty_six_variant_enum; - - #[derive(Debug)] pub enum Visible1 { _A(T), } - - #[repr(no_niche)] - #[derive(Debug)] pub enum Cloaked1 { _A(T), } - - // (N.B.: transparent enums must be univariant) - #[repr(transparent)] - #[derive(Debug)] pub enum Transparent { _A(T), } - - #[repr(transparent, no_niche)] - #[derive(Debug)] pub enum Shadowy { _A(T), } - - // including multivariant enums for completeness. Same notes apply - // here as above (assuming `T` is instantiated with `NonZeroU8`). - two_fifty_six_variant_enum!(Visible2); - - two_fifty_six_variant_enum!(#[repr(no_niche)] Cloaked2); -} - -fn main() { - // sanity-checks - assert_eq!(size_of::(), 2); - assert_eq!(size_of::(), 2); - assert_eq!(size_of::(), 2); - assert_eq!(size_of::(), 2); - - assert_eq!(size_of::>(), 2); - assert_eq!(size_of::>(), 2); - assert_eq!(size_of::>(), 2); - assert_eq!(size_of::>(), 2); - - assert_eq!(size_of::(), 2); - assert_eq!(size_of::(), 2); - assert_eq!(size_of::(), 2); // transparent enums are univariant - assert_eq!(size_of::(), 2); - assert_eq!(size_of::(), 4); - assert_eq!(size_of::(), 4); - - assert_eq!(size_of::>(), 2); - assert_eq!(size_of::>(), 2); - assert_eq!(size_of::>(), 2); - assert_eq!(size_of::>(), 2); - assert_eq!(size_of::>(), 4); - assert_eq!(size_of::>(), 4); - - // now the actual tests of no_niche: how do inputs above compose - // with `Option` type constructor. The cases with a `_+2` are the - // ones where no_niche fires. - assert_eq!(size_of::>(), 2); - assert_eq!(size_of::>(), 2+2); - assert_eq!(size_of::>(), 2); - assert_eq!(size_of::>(), 2+2); - - assert_eq!(size_of::>>(), 2); - assert_eq!(size_of::>>(), 2+2); - assert_eq!(size_of::>>(), 2); - assert_eq!(size_of::>>(), 2+2); - - assert_eq!(size_of::>(), 2); - assert_eq!(size_of::>(), 2+2); - assert_eq!(size_of::>(), 2); - assert_eq!(size_of::>(), 2+2); - // cannot use niche of multivariant payload - assert_eq!(size_of::>(), 4+2); - assert_eq!(size_of::>(), 4+2); - - assert_eq!(size_of::>>(), 2); - assert_eq!(size_of::>>(), 2+2); - assert_eq!(size_of::>>(), 2); - assert_eq!(size_of::>>(), 2+2); - // cannot use niche of multivariant payload - assert_eq!(size_of::>>(), 4+2); - assert_eq!(size_of::>>(), 4+2); -} - -macro two_fifty_six_variant_enum { - ($(#[$attr:meta])* $name:ident<$param:ident>) => { - #[derive(Debug)] $(#[$attr])* - pub enum $name<$param> { - _V00($param, u16), _V01(u16, $param), _V02($param, u16), _V03(u16, $param), - _V04($param, u16), _V05(u16, $param), _V06($param, u16), _V07(u16, $param), - _V08($param, u16), _V09(u16, $param), _V0a($param, u16), _V0b(u16, $param), - _V0c($param, u16), _V0d(u16, $param), _V0e($param, u16), _V0f(u16, $param), - - _V10($param, u16), _V11(u16, $param), _V12($param, u16), _V13(u16, $param), - _V14($param, u16), _V15(u16, $param), _V16($param, u16), _V17(u16, $param), - _V18($param, u16), _V19(u16, $param), _V1a($param, u16), _V1b(u16, $param), - _V1c($param, u16), _V1d(u16, $param), _V1e($param, u16), _V1f(u16, $param), - - _V20($param, u16), _V21(u16, $param), _V22($param, u16), _V23(u16, $param), - _V24($param, u16), _V25(u16, $param), _V26($param, u16), _V27(u16, $param), - _V28($param, u16), _V29(u16, $param), _V2a($param, u16), _V2b(u16, $param), - _V2c($param, u16), _V2d(u16, $param), _V2e($param, u16), _V2f(u16, $param), - - _V30($param, u16), _V31(u16, $param), _V32($param, u16), _V33(u16, $param), - _V34($param, u16), _V35(u16, $param), _V36($param, u16), _V37(u16, $param), - _V38($param, u16), _V39(u16, $param), _V3a($param, u16), _V3b(u16, $param), - _V3c($param, u16), _V3d(u16, $param), _V3e($param, u16), _V3f(u16, $param), - - _V40($param, u16), _V41(u16, $param), _V42($param, u16), _V43(u16, $param), - _V44($param, u16), _V45(u16, $param), _V46($param, u16), _V47(u16, $param), - _V48($param, u16), _V49(u16, $param), _V4a($param, u16), _V4b(u16, $param), - _V4c($param, u16), _V4d(u16, $param), _V4e($param, u16), _V4f(u16, $param), - - _V50($param, u16), _V51(u16, $param), _V52($param, u16), _V53(u16, $param), - _V54($param, u16), _V55(u16, $param), _V56($param, u16), _V57(u16, $param), - _V58($param, u16), _V59(u16, $param), _V5a($param, u16), _V5b(u16, $param), - _V5c($param, u16), _V5d(u16, $param), _V5e($param, u16), _V5f(u16, $param), - - _V60($param, u16), _V61(u16, $param), _V62($param, u16), _V63(u16, $param), - _V64($param, u16), _V65(u16, $param), _V66($param, u16), _V67(u16, $param), - _V68($param, u16), _V69(u16, $param), _V6a($param, u16), _V6b(u16, $param), - _V6c($param, u16), _V6d(u16, $param), _V6e($param, u16), _V6f(u16, $param), - - _V70($param, u16), _V71(u16, $param), _V72($param, u16), _V73(u16, $param), - _V74($param, u16), _V75(u16, $param), _V76($param, u16), _V77(u16, $param), - _V78($param, u16), _V79(u16, $param), _V7a($param, u16), _V7b(u16, $param), - _V7c($param, u16), _V7d(u16, $param), _V7e($param, u16), _V7f(u16, $param), - - _V80($param, u16), _V81(u16, $param), _V82($param, u16), _V83(u16, $param), - _V84($param, u16), _V85(u16, $param), _V86($param, u16), _V87(u16, $param), - _V88($param, u16), _V89(u16, $param), _V8a($param, u16), _V8b(u16, $param), - _V8c($param, u16), _V8d(u16, $param), _V8e($param, u16), _V8f(u16, $param), - - _V90($param, u16), _V91(u16, $param), _V92($param, u16), _V93(u16, $param), - _V94($param, u16), _V95(u16, $param), _V96($param, u16), _V97(u16, $param), - _V98($param, u16), _V99(u16, $param), _V9a($param, u16), _V9b(u16, $param), - _V9c($param, u16), _V9d(u16, $param), _V9e($param, u16), _V9f(u16, $param), - - _Va0($param, u16), _Va1(u16, $param), _Va2($param, u16), _Va3(u16, $param), - _Va4($param, u16), _Va5(u16, $param), _Va6($param, u16), _Va7(u16, $param), - _Va8($param, u16), _Va9(u16, $param), _Vaa($param, u16), _Vab(u16, $param), - _Vac($param, u16), _Vad(u16, $param), _Vae($param, u16), _Vaf(u16, $param), - - _Vb0($param, u16), _Vb1(u16, $param), _Vb2($param, u16), _Vb3(u16, $param), - _Vb4($param, u16), _Vb5(u16, $param), _Vb6($param, u16), _Vb7(u16, $param), - _Vb8($param, u16), _Vb9(u16, $param), _Vba($param, u16), _Vbb(u16, $param), - _Vbc($param, u16), _Vbd(u16, $param), _Vbe($param, u16), _Vbf(u16, $param), - - _Vc0($param, u16), _Vc1(u16, $param), _Vc2($param, u16), _Vc3(u16, $param), - _Vc4($param, u16), _Vc5(u16, $param), _Vc6($param, u16), _Vc7(u16, $param), - _Vc8($param, u16), _Vc9(u16, $param), _Vca($param, u16), _Vcb(u16, $param), - _Vcc($param, u16), _Vcd(u16, $param), _Vce($param, u16), _Vcf(u16, $param), - - _Vd0($param, u16), _Vd1(u16, $param), _Vd2($param, u16), _Vd3(u16, $param), - _Vd4($param, u16), _Vd5(u16, $param), _Vd6($param, u16), _Vd7(u16, $param), - _Vd8($param, u16), _Vd9(u16, $param), _Vda($param, u16), _Vdb(u16, $param), - _Vdc($param, u16), _Vdd(u16, $param), _Vde($param, u16), _Vdf(u16, $param), - - _Ve0($param, u16), _Ve1(u16, $param), _Ve2($param, u16), _Ve3(u16, $param), - _Ve4($param, u16), _Ve5(u16, $param), _Ve6($param, u16), _Ve7(u16, $param), - _Ve8($param, u16), _Ve9(u16, $param), _Vea($param, u16), _Veb(u16, $param), - _Vec($param, u16), _Ved(u16, $param), _Vee($param, u16), _Vef(u16, $param), - - _Vf0($param, u16), _Vf1(u16, $param), _Vf2($param, u16), _Vf3(u16, $param), - _Vf4($param, u16), _Vf5(u16, $param), _Vf6($param, u16), _Vf7(u16, $param), - _Vf8($param, u16), _Vf9(u16, $param), _Vfa($param, u16), _Vfb(u16, $param), - _Vfc($param, u16), _Vfd(u16, $param), _Vfe($param, u16), _Vff(u16, $param), - } - }, - - ($(#[$attr:meta])* $name:ident, $param:ty) => { - #[derive(Debug)] $(#[$attr])* - pub enum $name { - _V00($param, u16), _V01(u16, $param), _V02($param, u16), _V03(u16, $param), - _V04($param, u16), _V05(u16, $param), _V06($param, u16), _V07(u16, $param), - _V08($param, u16), _V09(u16, $param), _V0a($param, u16), _V0b(u16, $param), - _V0c($param, u16), _V0d(u16, $param), _V0e($param, u16), _V0f(u16, $param), - - _V10($param, u16), _V11(u16, $param), _V12($param, u16), _V13(u16, $param), - _V14($param, u16), _V15(u16, $param), _V16($param, u16), _V17(u16, $param), - _V18($param, u16), _V19(u16, $param), _V1a($param, u16), _V1b(u16, $param), - _V1c($param, u16), _V1d(u16, $param), _V1e($param, u16), _V1f(u16, $param), - - _V20($param, u16), _V21(u16, $param), _V22($param, u16), _V23(u16, $param), - _V24($param, u16), _V25(u16, $param), _V26($param, u16), _V27(u16, $param), - _V28($param, u16), _V29(u16, $param), _V2a($param, u16), _V2b(u16, $param), - _V2c($param, u16), _V2d(u16, $param), _V2e($param, u16), _V2f(u16, $param), - - _V30($param, u16), _V31(u16, $param), _V32($param, u16), _V33(u16, $param), - _V34($param, u16), _V35(u16, $param), _V36($param, u16), _V37(u16, $param), - _V38($param, u16), _V39(u16, $param), _V3a($param, u16), _V3b(u16, $param), - _V3c($param, u16), _V3d(u16, $param), _V3e($param, u16), _V3f(u16, $param), - - _V40($param, u16), _V41(u16, $param), _V42($param, u16), _V43(u16, $param), - _V44($param, u16), _V45(u16, $param), _V46($param, u16), _V47(u16, $param), - _V48($param, u16), _V49(u16, $param), _V4a($param, u16), _V4b(u16, $param), - _V4c($param, u16), _V4d(u16, $param), _V4e($param, u16), _V4f(u16, $param), - - _V50($param, u16), _V51(u16, $param), _V52($param, u16), _V53(u16, $param), - _V54($param, u16), _V55(u16, $param), _V56($param, u16), _V57(u16, $param), - _V58($param, u16), _V59(u16, $param), _V5a($param, u16), _V5b(u16, $param), - _V5c($param, u16), _V5d(u16, $param), _V5e($param, u16), _V5f(u16, $param), - - _V60($param, u16), _V61(u16, $param), _V62($param, u16), _V63(u16, $param), - _V64($param, u16), _V65(u16, $param), _V66($param, u16), _V67(u16, $param), - _V68($param, u16), _V69(u16, $param), _V6a($param, u16), _V6b(u16, $param), - _V6c($param, u16), _V6d(u16, $param), _V6e($param, u16), _V6f(u16, $param), - - _V70($param, u16), _V71(u16, $param), _V72($param, u16), _V73(u16, $param), - _V74($param, u16), _V75(u16, $param), _V76($param, u16), _V77(u16, $param), - _V78($param, u16), _V79(u16, $param), _V7a($param, u16), _V7b(u16, $param), - _V7c($param, u16), _V7d(u16, $param), _V7e($param, u16), _V7f(u16, $param), - - _V80($param, u16), _V81(u16, $param), _V82($param, u16), _V83(u16, $param), - _V84($param, u16), _V85(u16, $param), _V86($param, u16), _V87(u16, $param), - _V88($param, u16), _V89(u16, $param), _V8a($param, u16), _V8b(u16, $param), - _V8c($param, u16), _V8d(u16, $param), _V8e($param, u16), _V8f(u16, $param), - - _V90($param, u16), _V91(u16, $param), _V92($param, u16), _V93(u16, $param), - _V94($param, u16), _V95(u16, $param), _V96($param, u16), _V97(u16, $param), - _V98($param, u16), _V99(u16, $param), _V9a($param, u16), _V9b(u16, $param), - _V9c($param, u16), _V9d(u16, $param), _V9e($param, u16), _V9f(u16, $param), - - _Va0($param, u16), _Va1(u16, $param), _Va2($param, u16), _Va3(u16, $param), - _Va4($param, u16), _Va5(u16, $param), _Va6($param, u16), _Va7(u16, $param), - _Va8($param, u16), _Va9(u16, $param), _Vaa($param, u16), _Vab(u16, $param), - _Vac($param, u16), _Vad(u16, $param), _Vae($param, u16), _Vaf(u16, $param), - - _Vb0($param, u16), _Vb1(u16, $param), _Vb2($param, u16), _Vb3(u16, $param), - _Vb4($param, u16), _Vb5(u16, $param), _Vb6($param, u16), _Vb7(u16, $param), - _Vb8($param, u16), _Vb9(u16, $param), _Vba($param, u16), _Vbb(u16, $param), - _Vbc($param, u16), _Vbd(u16, $param), _Vbe($param, u16), _Vbf(u16, $param), - - _Vc0($param, u16), _Vc1(u16, $param), _Vc2($param, u16), _Vc3(u16, $param), - _Vc4($param, u16), _Vc5(u16, $param), _Vc6($param, u16), _Vc7(u16, $param), - _Vc8($param, u16), _Vc9(u16, $param), _Vca($param, u16), _Vcb(u16, $param), - _Vcc($param, u16), _Vcd(u16, $param), _Vce($param, u16), _Vcf(u16, $param), - - _Vd0($param, u16), _Vd1(u16, $param), _Vd2($param, u16), _Vd3(u16, $param), - _Vd4($param, u16), _Vd5(u16, $param), _Vd6($param, u16), _Vd7(u16, $param), - _Vd8($param, u16), _Vd9(u16, $param), _Vda($param, u16), _Vdb(u16, $param), - _Vdc($param, u16), _Vdd(u16, $param), _Vde($param, u16), _Vdf(u16, $param), - - _Ve0($param, u16), _Ve1(u16, $param), _Ve2($param, u16), _Ve3(u16, $param), - _Ve4($param, u16), _Ve5(u16, $param), _Ve6($param, u16), _Ve7(u16, $param), - _Ve8($param, u16), _Ve9(u16, $param), _Vea($param, u16), _Veb(u16, $param), - _Vec($param, u16), _Ved(u16, $param), _Vee($param, u16), _Vef(u16, $param), - - _Vf0($param, u16), _Vf1(u16, $param), _Vf2($param, u16), _Vf3(u16, $param), - _Vf4($param, u16), _Vf5(u16, $param), _Vf6($param, u16), _Vf7(u16, $param), - _Vf8($param, u16), _Vf9(u16, $param), _Vfa($param, u16), _Vfb(u16, $param), - _Vfc($param, u16), _Vfd(u16, $param), _Vfe($param, u16), _Vff(u16, $param), - } - } -} diff --git a/src/tools/clippy/clippy_lints/src/non_copy_const.rs b/src/tools/clippy/clippy_lints/src/non_copy_const.rs index a1ef32ae60805..6bce5fbd4c1fe 100644 --- a/src/tools/clippy/clippy_lints/src/non_copy_const.rs +++ b/src/tools/clippy/clippy_lints/src/non_copy_const.rs @@ -148,7 +148,7 @@ fn is_value_unfrozen_raw<'tcx>( match val.ty().kind() { // the fact that we have to dig into every structs to search enums // leads us to the point checking `UnsafeCell` directly is the only option. - ty::Adt(ty_def, ..) if Some(ty_def.did()) == cx.tcx.lang_items().unsafe_cell_type() => true, + ty::Adt(ty_def, ..) if ty_def.is_unsafe_cell() => true, ty::Array(..) | ty::Adt(..) | ty::Tuple(..) => { let val = cx.tcx.destructure_mir_constant(cx.param_env, val); val.fields.iter().any(|field| inner(cx, *field)) From 8d9f609d0d4465285ac9f0257c706c559644fef5 Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Thu, 7 Jul 2022 11:19:57 +0000 Subject: [PATCH 02/29] Comment update --- compiler/rustc_lint/src/types.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/compiler/rustc_lint/src/types.rs b/compiler/rustc_lint/src/types.rs index 4ed9d9b27b297..aca481df2e113 100644 --- a/compiler/rustc_lint/src/types.rs +++ b/compiler/rustc_lint/src/types.rs @@ -703,8 +703,7 @@ fn ty_is_known_nonnull<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>, mode: CItemKi return true; } - // Types with a `#[repr(no_niche)]` attribute have their niche hidden. - // The attribute is used by the UnsafeCell for example (the only use so far). + // `UnsafeCell` has its niche hidden. if def.is_unsafe_cell() { return false; } From 4bfba76a3da28d780be3cb31fd6269b8bc6183df Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Fri, 8 Jul 2022 14:28:19 +0000 Subject: [PATCH 03/29] Add tests for libstd types --- src/test/ui/layout/unsafe-cell-hides-niche.rs | 22 ++++++++++++++----- 1 file changed, 17 insertions(+), 5 deletions(-) diff --git a/src/test/ui/layout/unsafe-cell-hides-niche.rs b/src/test/ui/layout/unsafe-cell-hides-niche.rs index eb65756a5f643..f6a8e0de27ad0 100644 --- a/src/test/ui/layout/unsafe-cell-hides-niche.rs +++ b/src/test/ui/layout/unsafe-cell-hides-niche.rs @@ -5,9 +5,10 @@ // run-pass -use std::cell::UnsafeCell; +use std::cell::{UnsafeCell, RefCell, Cell}; use std::mem::size_of; use std::num::NonZeroU32 as N32; +use std::sync::{Mutex, RwLock}; struct Wrapper(T); @@ -18,12 +19,23 @@ struct NoNiche(UnsafeCell); fn main() { assert_eq!(size_of::>>(), 8); - assert_eq!(size_of::>>(), 4); + assert_eq!(size_of::>>(), 4); // (✓ niche opt) assert_eq!(size_of::>>(), 8); - assert_eq!(size_of::>>(), 4); + assert_eq!(size_of::>>(), 4); // (✓ niche opt) assert_eq!(size_of::>>(), 8); - assert_eq!(size_of::>>(), 8); + assert_eq!(size_of::>>(), 8); // (✗ niche opt) assert_eq!(size_of::>>(), 8); - assert_eq!(size_of::>>(), 8); + assert_eq!(size_of::>>(), 8); // (✗ niche opt) + + assert_eq!(size_of::< UnsafeCell<&()> >(), 8); + assert_eq!(size_of::>>(), 16); // (✗ niche opt) + assert_eq!(size_of::< Cell<&()> >(), 8); + assert_eq!(size_of::>>(), 16); // (✗ niche opt) + assert_eq!(size_of::< RefCell<&()> >(), 16); + assert_eq!(size_of::>>(), 24); // (✗ niche opt) + assert_eq!(size_of::< RwLock<&()> >(), 24); + assert_eq!(size_of::>>(), 32); // (✗ niche opt) + assert_eq!(size_of::< Mutex<&()> >(), 16); + assert_eq!(size_of::>>(), 24); // (✗ niche opt) } From 69b1b3c011143b573c904f0759d187588cc457c0 Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Fri, 8 Jul 2022 14:47:25 +0000 Subject: [PATCH 04/29] Create a custom layout path for UnsafeCell instead of piggy backing on the layout_scalar_valid_range logic --- compiler/rustc_middle/src/ty/layout.rs | 60 ++++++++++++------- src/test/ui/layout/unsafe-cell-hides-niche.rs | 9 +++ 2 files changed, 48 insertions(+), 21 deletions(-) diff --git a/compiler/rustc_middle/src/ty/layout.rs b/compiler/rustc_middle/src/ty/layout.rs index cef8a1dba7f8d..6d87328ef5daa 100644 --- a/compiler/rustc_middle/src/ty/layout.rs +++ b/compiler/rustc_middle/src/ty/layout.rs @@ -1076,6 +1076,34 @@ impl<'tcx> LayoutCx<'tcx, TyCtxt<'tcx>> { let mut st = self.univariant_uninterned(ty, &variants[v], &def.repr(), kind)?; st.variants = Variants::Single { index: v }; + + if def.is_unsafe_cell() { + let fill = |scalar: &mut _| match scalar { + Scalar::Initialized { value, valid_range } => { + *valid_range = WrappingRange::full(value.size(dl)) + } + // Already doesn't have any niches + Scalar::Union { .. } => {} + }; + match &mut st.abi { + Abi::Uninhabited => {} + Abi::Scalar(scalar) => fill(scalar), + Abi::ScalarPair(a, b) => { + fill(a); + fill(b); + } + Abi::Vector { element, count: _ } => { + // Until we support types other than floats and integers in SIMD, + // `element` must already be a full for its range, so there's nothing to + // do here. + assert!(element.is_always_valid(dl)); + } + Abi::Aggregate { sized: _ } => {} + } + st.largest_niche = None; + return Ok(tcx.intern_layout(st)); + } + let (start, end) = self.tcx.layout_scalar_valid_range(def.did()); match st.abi { Abi::Scalar(ref mut scalar) | Abi::ScalarPair(ref mut scalar, _) => { @@ -1102,29 +1130,19 @@ impl<'tcx> LayoutCx<'tcx, TyCtxt<'tcx>> { assert!(valid_range.end >= end); valid_range.end = end; } - if def.is_unsafe_cell() { - match scalar { - Scalar::Initialized { value, valid_range } => { - *valid_range = WrappingRange::full(value.size(dl)) - } - // Already doesn't have any niches - Scalar::Union { .. } => {} - } - st.largest_niche = None; - } else { - // Update `largest_niche` if we have introduced a larger niche. - let niche = Niche::from_scalar(dl, Size::ZERO, *scalar); - if let Some(niche) = niche { - match st.largest_niche { - Some(largest_niche) => { - // Replace the existing niche even if they're equal, - // because this one is at a lower offset. - if largest_niche.available(dl) <= niche.available(dl) { - st.largest_niche = Some(niche); - } + + // Update `largest_niche` if we have introduced a larger niche. + let niche = Niche::from_scalar(dl, Size::ZERO, *scalar); + if let Some(niche) = niche { + match st.largest_niche { + Some(largest_niche) => { + // Replace the existing niche even if they're equal, + // because this one is at a lower offset. + if largest_niche.available(dl) <= niche.available(dl) { + st.largest_niche = Some(niche); } - None => st.largest_niche = Some(niche), } + None => st.largest_niche = Some(niche), } } } diff --git a/src/test/ui/layout/unsafe-cell-hides-niche.rs b/src/test/ui/layout/unsafe-cell-hides-niche.rs index f6a8e0de27ad0..2d3bb1d23c093 100644 --- a/src/test/ui/layout/unsafe-cell-hides-niche.rs +++ b/src/test/ui/layout/unsafe-cell-hides-niche.rs @@ -38,4 +38,13 @@ fn main() { assert_eq!(size_of::>>(), 32); // (✗ niche opt) assert_eq!(size_of::< Mutex<&()> >(), 16); assert_eq!(size_of::>>(), 24); // (✗ niche opt) + + assert_eq!(size_of::< UnsafeCell<&[i32]> >(), 16); + assert_eq!(size_of::>>(), 24); // (✗ niche opt) + assert_eq!(size_of::< UnsafeCell<(&(), &())> >(), 16); + assert_eq!(size_of::>>(), 24); // (✗ niche opt) + + trait Trait {} + assert_eq!(size_of::< UnsafeCell<&dyn Trait> >(), 16); + assert_eq!(size_of::>>(), 24); // (✗ niche opt) } From bfb3afe893ceea7451340a373da2dfc7b0e361a6 Mon Sep 17 00:00:00 2001 From: Joshua Nelson Date: Sun, 10 Jul 2022 17:32:37 -0500 Subject: [PATCH 05/29] Add some autolabels for A-bootstrap and T-infra --- triagebot.toml | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/triagebot.toml b/triagebot.toml index ba9ed20cc64a2..8d9fab84ca13e 100644 --- a/triagebot.toml +++ b/triagebot.toml @@ -165,6 +165,19 @@ exclude_labels = [ "T-*", ] +[autolabel."A-bootstrap"] +trigger_files = [ + "x.py", + "src/bootstrap", + "src/tools/rust-installer", +] + +[autolabel."T-infra"] +trigger_files = [ + "src/ci", + "src/tools/bump-stage0", +] + [notify-zulip."I-prioritize"] zulip_stream = 245100 # #t-compiler/wg-prioritization/alerts topic = "#{number} {title}" From 423915590b08896ecc845b8b22910cb98c4c7e36 Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Mon, 11 Jul 2022 10:11:28 +0000 Subject: [PATCH 06/29] More obvious closure name --- compiler/rustc_middle/src/ty/layout.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/compiler/rustc_middle/src/ty/layout.rs b/compiler/rustc_middle/src/ty/layout.rs index 6d87328ef5daa..8cbc0169bc7a4 100644 --- a/compiler/rustc_middle/src/ty/layout.rs +++ b/compiler/rustc_middle/src/ty/layout.rs @@ -1078,7 +1078,7 @@ impl<'tcx> LayoutCx<'tcx, TyCtxt<'tcx>> { st.variants = Variants::Single { index: v }; if def.is_unsafe_cell() { - let fill = |scalar: &mut _| match scalar { + let hide_niches = |scalar: &mut _| match scalar { Scalar::Initialized { value, valid_range } => { *valid_range = WrappingRange::full(value.size(dl)) } @@ -1087,10 +1087,10 @@ impl<'tcx> LayoutCx<'tcx, TyCtxt<'tcx>> { }; match &mut st.abi { Abi::Uninhabited => {} - Abi::Scalar(scalar) => fill(scalar), + Abi::Scalar(scalar) => hide_niches(scalar), Abi::ScalarPair(a, b) => { - fill(a); - fill(b); + hide_niches(a); + hide_niches(b); } Abi::Vector { element, count: _ } => { // Until we support types other than floats and integers in SIMD, From 984db78d771ec67d781e954da759dbea8667197a Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Mon, 11 Jul 2022 10:25:41 +0000 Subject: [PATCH 07/29] Hide niches in SIMD types, too --- compiler/rustc_middle/src/ty/layout.rs | 7 +------ src/test/ui/layout/unsafe-cell-hides-niche.rs | 8 ++++++++ 2 files changed, 9 insertions(+), 6 deletions(-) diff --git a/compiler/rustc_middle/src/ty/layout.rs b/compiler/rustc_middle/src/ty/layout.rs index 8cbc0169bc7a4..1ed41db099ca0 100644 --- a/compiler/rustc_middle/src/ty/layout.rs +++ b/compiler/rustc_middle/src/ty/layout.rs @@ -1092,12 +1092,7 @@ impl<'tcx> LayoutCx<'tcx, TyCtxt<'tcx>> { hide_niches(a); hide_niches(b); } - Abi::Vector { element, count: _ } => { - // Until we support types other than floats and integers in SIMD, - // `element` must already be a full for its range, so there's nothing to - // do here. - assert!(element.is_always_valid(dl)); - } + Abi::Vector { element, count: _ } => hide_niches(element), Abi::Aggregate { sized: _ } => {} } st.largest_niche = None; diff --git a/src/test/ui/layout/unsafe-cell-hides-niche.rs b/src/test/ui/layout/unsafe-cell-hides-niche.rs index 2d3bb1d23c093..bb2156a5da727 100644 --- a/src/test/ui/layout/unsafe-cell-hides-niche.rs +++ b/src/test/ui/layout/unsafe-cell-hides-niche.rs @@ -5,6 +5,8 @@ // run-pass +#![feature(repr_simd)] + use std::cell::{UnsafeCell, RefCell, Cell}; use std::mem::size_of; use std::num::NonZeroU32 as N32; @@ -47,4 +49,10 @@ fn main() { trait Trait {} assert_eq!(size_of::< UnsafeCell<&dyn Trait> >(), 16); assert_eq!(size_of::>>(), 24); // (✗ niche opt) + + #[repr(simd)] + pub struct Vec4([T; 4]); + + assert_eq!(size_of::< UnsafeCell> >(), 16); + assert_eq!(size_of::>>>(), 32); // (✗ niche opt) } From 3f4cf59323304a2e785aba564a6eb3bd473d5499 Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Mon, 11 Jul 2022 10:29:02 +0000 Subject: [PATCH 08/29] Move checks to compile-time --- src/test/ui/layout/unsafe-cell-hides-niche.rs | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/test/ui/layout/unsafe-cell-hides-niche.rs b/src/test/ui/layout/unsafe-cell-hides-niche.rs index bb2156a5da727..385472ac88a7d 100644 --- a/src/test/ui/layout/unsafe-cell-hides-niche.rs +++ b/src/test/ui/layout/unsafe-cell-hides-niche.rs @@ -3,7 +3,7 @@ // test checks that an `Option>` has the same // size in memory as an `Option>` (namely, 8 bytes). -// run-pass +// check-pass #![feature(repr_simd)] @@ -19,6 +19,13 @@ struct Transparent(T); struct NoNiche(UnsafeCell); +// Overwriting the runtime assertion and making it a compile-time assertion +macro_rules! assert_eq { + ($a:expr, $b:literal) => {{ + const _: () = assert!($a == $b); + }}; +} + fn main() { assert_eq!(size_of::>>(), 8); assert_eq!(size_of::>>(), 4); // (✓ niche opt) From af8536e32ff8840bb41c65a438ccf33568548e02 Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Mon, 11 Jul 2022 10:30:50 +0000 Subject: [PATCH 09/29] Simplify assertion macro --- src/test/ui/layout/unsafe-cell-hides-niche.rs | 57 +++++++++---------- 1 file changed, 28 insertions(+), 29 deletions(-) diff --git a/src/test/ui/layout/unsafe-cell-hides-niche.rs b/src/test/ui/layout/unsafe-cell-hides-niche.rs index 385472ac88a7d..f5c1fe1320c56 100644 --- a/src/test/ui/layout/unsafe-cell-hides-niche.rs +++ b/src/test/ui/layout/unsafe-cell-hides-niche.rs @@ -8,7 +8,6 @@ #![feature(repr_simd)] use std::cell::{UnsafeCell, RefCell, Cell}; -use std::mem::size_of; use std::num::NonZeroU32 as N32; use std::sync::{Mutex, RwLock}; @@ -21,45 +20,45 @@ struct NoNiche(UnsafeCell); // Overwriting the runtime assertion and making it a compile-time assertion macro_rules! assert_eq { - ($a:expr, $b:literal) => {{ - const _: () = assert!($a == $b); + ($a:ty, $b:literal) => {{ + const _: () = assert!(std::mem::size_of::<$a>() == $b); }}; } fn main() { - assert_eq!(size_of::>>(), 8); - assert_eq!(size_of::>>(), 4); // (✓ niche opt) - assert_eq!(size_of::>>(), 8); - assert_eq!(size_of::>>(), 4); // (✓ niche opt) - assert_eq!(size_of::>>(), 8); - assert_eq!(size_of::>>(), 8); // (✗ niche opt) + assert_eq!(Option>, 8); + assert_eq!(Option>, 4); // (✓ niche opt) + assert_eq!(Option>, 8); + assert_eq!(Option>, 4); // (✓ niche opt) + assert_eq!(Option>, 8); + assert_eq!(Option>, 8); // (✗ niche opt) - assert_eq!(size_of::>>(), 8); - assert_eq!(size_of::>>(), 8); // (✗ niche opt) + assert_eq!(Option>, 8); + assert_eq!(Option>, 8); // (✗ niche opt) - assert_eq!(size_of::< UnsafeCell<&()> >(), 8); - assert_eq!(size_of::>>(), 16); // (✗ niche opt) - assert_eq!(size_of::< Cell<&()> >(), 8); - assert_eq!(size_of::>>(), 16); // (✗ niche opt) - assert_eq!(size_of::< RefCell<&()> >(), 16); - assert_eq!(size_of::>>(), 24); // (✗ niche opt) - assert_eq!(size_of::< RwLock<&()> >(), 24); - assert_eq!(size_of::>>(), 32); // (✗ niche opt) - assert_eq!(size_of::< Mutex<&()> >(), 16); - assert_eq!(size_of::>>(), 24); // (✗ niche opt) + assert_eq!( UnsafeCell<&()> , 8); + assert_eq!(Option>, 16); // (✗ niche opt) + assert_eq!( Cell<&()> , 8); + assert_eq!(Option< Cell<&()>>, 16); // (✗ niche opt) + assert_eq!( RefCell<&()> , 16); + assert_eq!(Option< RefCell<&()>>, 24); // (✗ niche opt) + assert_eq!( RwLock<&()> , 24); + assert_eq!(Option< RwLock<&()>>, 32); // (✗ niche opt) + assert_eq!( Mutex<&()> , 16); + assert_eq!(Option< Mutex<&()>>, 24); // (✗ niche opt) - assert_eq!(size_of::< UnsafeCell<&[i32]> >(), 16); - assert_eq!(size_of::>>(), 24); // (✗ niche opt) - assert_eq!(size_of::< UnsafeCell<(&(), &())> >(), 16); - assert_eq!(size_of::>>(), 24); // (✗ niche opt) + assert_eq!( UnsafeCell<&[i32]> , 16); + assert_eq!(Option>, 24); // (✗ niche opt) + assert_eq!( UnsafeCell<(&(), &())> , 16); + assert_eq!(Option>, 24); // (✗ niche opt) trait Trait {} - assert_eq!(size_of::< UnsafeCell<&dyn Trait> >(), 16); - assert_eq!(size_of::>>(), 24); // (✗ niche opt) + assert_eq!( UnsafeCell<&dyn Trait> , 16); + assert_eq!(Option>, 24); // (✗ niche opt) #[repr(simd)] pub struct Vec4([T; 4]); - assert_eq!(size_of::< UnsafeCell> >(), 16); - assert_eq!(size_of::>>>(), 32); // (✗ niche opt) + assert_eq!( UnsafeCell> , 16); + assert_eq!(Option>>, 32); // (✗ niche opt) } From fef596f6a243d311dc50b50f83f8339e326f1f66 Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Mon, 11 Jul 2022 10:31:21 +0000 Subject: [PATCH 10/29] Rename assertion macro --- src/test/ui/layout/unsafe-cell-hides-niche.rs | 54 +++++++++---------- 1 file changed, 27 insertions(+), 27 deletions(-) diff --git a/src/test/ui/layout/unsafe-cell-hides-niche.rs b/src/test/ui/layout/unsafe-cell-hides-niche.rs index f5c1fe1320c56..7fb55d8219ef8 100644 --- a/src/test/ui/layout/unsafe-cell-hides-niche.rs +++ b/src/test/ui/layout/unsafe-cell-hides-niche.rs @@ -19,46 +19,46 @@ struct Transparent(T); struct NoNiche(UnsafeCell); // Overwriting the runtime assertion and making it a compile-time assertion -macro_rules! assert_eq { +macro_rules! assert_size { ($a:ty, $b:literal) => {{ const _: () = assert!(std::mem::size_of::<$a>() == $b); }}; } fn main() { - assert_eq!(Option>, 8); - assert_eq!(Option>, 4); // (✓ niche opt) - assert_eq!(Option>, 8); - assert_eq!(Option>, 4); // (✓ niche opt) - assert_eq!(Option>, 8); - assert_eq!(Option>, 8); // (✗ niche opt) + assert_size!(Option>, 8); + assert_size!(Option>, 4); // (✓ niche opt) + assert_size!(Option>, 8); + assert_size!(Option>, 4); // (✓ niche opt) + assert_size!(Option>, 8); + assert_size!(Option>, 8); // (✗ niche opt) - assert_eq!(Option>, 8); - assert_eq!(Option>, 8); // (✗ niche opt) + assert_size!(Option>, 8); + assert_size!(Option>, 8); // (✗ niche opt) - assert_eq!( UnsafeCell<&()> , 8); - assert_eq!(Option>, 16); // (✗ niche opt) - assert_eq!( Cell<&()> , 8); - assert_eq!(Option< Cell<&()>>, 16); // (✗ niche opt) - assert_eq!( RefCell<&()> , 16); - assert_eq!(Option< RefCell<&()>>, 24); // (✗ niche opt) - assert_eq!( RwLock<&()> , 24); - assert_eq!(Option< RwLock<&()>>, 32); // (✗ niche opt) - assert_eq!( Mutex<&()> , 16); - assert_eq!(Option< Mutex<&()>>, 24); // (✗ niche opt) + assert_size!( UnsafeCell<&()> , 8); + assert_size!(Option>, 16); // (✗ niche opt) + assert_size!( Cell<&()> , 8); + assert_size!(Option< Cell<&()>>, 16); // (✗ niche opt) + assert_size!( RefCell<&()> , 16); + assert_size!(Option< RefCell<&()>>, 24); // (✗ niche opt) + assert_size!( RwLock<&()> , 24); + assert_size!(Option< RwLock<&()>>, 32); // (✗ niche opt) + assert_size!( Mutex<&()> , 16); + assert_size!(Option< Mutex<&()>>, 24); // (✗ niche opt) - assert_eq!( UnsafeCell<&[i32]> , 16); - assert_eq!(Option>, 24); // (✗ niche opt) - assert_eq!( UnsafeCell<(&(), &())> , 16); - assert_eq!(Option>, 24); // (✗ niche opt) + assert_size!( UnsafeCell<&[i32]> , 16); + assert_size!(Option>, 24); // (✗ niche opt) + assert_size!( UnsafeCell<(&(), &())> , 16); + assert_size!(Option>, 24); // (✗ niche opt) trait Trait {} - assert_eq!( UnsafeCell<&dyn Trait> , 16); - assert_eq!(Option>, 24); // (✗ niche opt) + assert_size!( UnsafeCell<&dyn Trait> , 16); + assert_size!(Option>, 24); // (✗ niche opt) #[repr(simd)] pub struct Vec4([T; 4]); - assert_eq!( UnsafeCell> , 16); - assert_eq!(Option>>, 32); // (✗ niche opt) + assert_size!( UnsafeCell> , 16); + assert_size!(Option>>, 32); // (✗ niche opt) } From 9a204509d2fe9d0ea72cb79ed6e341de7a3bcacb Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Mon, 11 Jul 2022 10:34:01 +0000 Subject: [PATCH 11/29] Show sizes in error output --- src/test/ui/layout/unsafe-cell-hides-niche.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/test/ui/layout/unsafe-cell-hides-niche.rs b/src/test/ui/layout/unsafe-cell-hides-niche.rs index 7fb55d8219ef8..21ff0cb1e5527 100644 --- a/src/test/ui/layout/unsafe-cell-hides-niche.rs +++ b/src/test/ui/layout/unsafe-cell-hides-niche.rs @@ -18,10 +18,12 @@ struct Transparent(T); struct NoNiche(UnsafeCell); +struct Size; + // Overwriting the runtime assertion and making it a compile-time assertion macro_rules! assert_size { ($a:ty, $b:literal) => {{ - const _: () = assert!(std::mem::size_of::<$a>() == $b); + const _: Size::<$b> = Size::<{std::mem::size_of::<$a>()}>; }}; } From fcd7207d0e5ab4a9598e3b6caf6248134e5f95d6 Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Mon, 11 Jul 2022 10:43:47 +0000 Subject: [PATCH 12/29] Make tests work on 32 bit and 64 bit --- src/test/ui/layout/unsafe-cell-hides-niche.rs | 41 ++++++++++--------- 1 file changed, 22 insertions(+), 19 deletions(-) diff --git a/src/test/ui/layout/unsafe-cell-hides-niche.rs b/src/test/ui/layout/unsafe-cell-hides-niche.rs index 21ff0cb1e5527..2833f49a27bf6 100644 --- a/src/test/ui/layout/unsafe-cell-hides-niche.rs +++ b/src/test/ui/layout/unsafe-cell-hides-niche.rs @@ -8,6 +8,7 @@ #![feature(repr_simd)] use std::cell::{UnsafeCell, RefCell, Cell}; +use std::mem::size_of; use std::num::NonZeroU32 as N32; use std::sync::{Mutex, RwLock}; @@ -22,11 +23,13 @@ struct Size; // Overwriting the runtime assertion and making it a compile-time assertion macro_rules! assert_size { - ($a:ty, $b:literal) => {{ - const _: Size::<$b> = Size::<{std::mem::size_of::<$a>()}>; + ($a:ty, $b:expr) => {{ + const _: Size::<{$b}> = Size::<{size_of::<$a>()}>; }}; } +const PTR_SIZE: usize = std::mem::size_of::<*const ()>(); + fn main() { assert_size!(Option>, 8); assert_size!(Option>, 4); // (✓ niche opt) @@ -38,25 +41,25 @@ fn main() { assert_size!(Option>, 8); assert_size!(Option>, 8); // (✗ niche opt) - assert_size!( UnsafeCell<&()> , 8); - assert_size!(Option>, 16); // (✗ niche opt) - assert_size!( Cell<&()> , 8); - assert_size!(Option< Cell<&()>>, 16); // (✗ niche opt) - assert_size!( RefCell<&()> , 16); - assert_size!(Option< RefCell<&()>>, 24); // (✗ niche opt) - assert_size!( RwLock<&()> , 24); - assert_size!(Option< RwLock<&()>>, 32); // (✗ niche opt) - assert_size!( Mutex<&()> , 16); - assert_size!(Option< Mutex<&()>>, 24); // (✗ niche opt) - - assert_size!( UnsafeCell<&[i32]> , 16); - assert_size!(Option>, 24); // (✗ niche opt) - assert_size!( UnsafeCell<(&(), &())> , 16); - assert_size!(Option>, 24); // (✗ niche opt) + assert_size!( UnsafeCell<&()> , PTR_SIZE); + assert_size!(Option>, PTR_SIZE * 2); // (✗ niche opt) + assert_size!( Cell<&()> , PTR_SIZE); + assert_size!(Option< Cell<&()>>, PTR_SIZE * 2); // (✗ niche opt) + assert_size!( RefCell<&()> , PTR_SIZE * 2); + assert_size!(Option< RefCell<&()>>, PTR_SIZE * 3); // (✗ niche opt) + assert_size!( RwLock<&()> , if cfg!(target_pointer_width = "32") { 16 } else { 24 }); + assert_size!(Option< RwLock<&()>>, if cfg!(target_pointer_width = "32") { 20 } else { 32 }); // (✗ niche opt) + assert_size!( Mutex<&()> , if cfg!(target_pointer_width = "32") { 12 } else { 16 }); + assert_size!(Option< Mutex<&()>>, if cfg!(target_pointer_width = "32") { 16 } else { 24 }); // (✗ niche opt) + + assert_size!( UnsafeCell<&[i32]> , PTR_SIZE * 2); + assert_size!(Option>, PTR_SIZE * 3); // (✗ niche opt) + assert_size!( UnsafeCell<(&(), &())> , PTR_SIZE * 2); + assert_size!(Option>, PTR_SIZE * 3); // (✗ niche opt) trait Trait {} - assert_size!( UnsafeCell<&dyn Trait> , 16); - assert_size!(Option>, 24); // (✗ niche opt) + assert_size!( UnsafeCell<&dyn Trait> , PTR_SIZE * 2); + assert_size!(Option>, PTR_SIZE * 3); // (✗ niche opt) #[repr(simd)] pub struct Vec4([T; 4]); From 8440208eb13ec1f680592b9a7793a67f2b1be15e Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Mon, 11 Jul 2022 11:07:03 +0000 Subject: [PATCH 13/29] tidy --- src/test/ui/layout/unsafe-cell-hides-niche.rs | 20 +++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) diff --git a/src/test/ui/layout/unsafe-cell-hides-niche.rs b/src/test/ui/layout/unsafe-cell-hides-niche.rs index 2833f49a27bf6..1d0e1fce178d0 100644 --- a/src/test/ui/layout/unsafe-cell-hides-niche.rs +++ b/src/test/ui/layout/unsafe-cell-hides-niche.rs @@ -47,10 +47,22 @@ fn main() { assert_size!(Option< Cell<&()>>, PTR_SIZE * 2); // (✗ niche opt) assert_size!( RefCell<&()> , PTR_SIZE * 2); assert_size!(Option< RefCell<&()>>, PTR_SIZE * 3); // (✗ niche opt) - assert_size!( RwLock<&()> , if cfg!(target_pointer_width = "32") { 16 } else { 24 }); - assert_size!(Option< RwLock<&()>>, if cfg!(target_pointer_width = "32") { 20 } else { 32 }); // (✗ niche opt) - assert_size!( Mutex<&()> , if cfg!(target_pointer_width = "32") { 12 } else { 16 }); - assert_size!(Option< Mutex<&()>>, if cfg!(target_pointer_width = "32") { 16 } else { 24 }); // (✗ niche opt) + assert_size!( + RwLock<&()>, + if cfg!(target_pointer_width = "32") { 16 } else { 24 } + ); + assert_size!( + Option>, + if cfg!(target_pointer_width = "32") { 20 } else { 32 } + ); // (✗ niche opt) + assert_size!( + Mutex<&()> , + if cfg!(target_pointer_width = "32") { 12 } else { 16 } + ); + assert_size!( + Option>, + if cfg!(target_pointer_width = "32") { 16 } else { 24 } + ); // (✗ niche opt) assert_size!( UnsafeCell<&[i32]> , PTR_SIZE * 2); assert_size!(Option>, PTR_SIZE * 3); // (✗ niche opt) From b608043d06378727829ccd9652a2648fc3a05f36 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 10 Jun 2022 21:44:57 -0700 Subject: [PATCH 14/29] factor 'is this type allowed as union field on stable' into separate function --- compiler/rustc_passes/src/stability.rs | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/compiler/rustc_passes/src/stability.rs b/compiler/rustc_passes/src/stability.rs index 12050dceb60a6..a1697978d66a3 100644 --- a/compiler/rustc_passes/src/stability.rs +++ b/compiler/rustc_passes/src/stability.rs @@ -772,13 +772,21 @@ impl<'tcx> Visitor<'tcx> for Checker<'tcx> { let ty = self.tcx.type_of(item.def_id); let ty::Adt(adt_def, substs) = ty.kind() else { bug!() }; + #[allow(rustc::usage_of_qualified_ty)] // `Ty` is the wrong type here, we really want `ty::Ty`. + fn allowed_union_field<'tcx>( + tcx: TyCtxt<'tcx>, + param_env: ty::ParamEnv<'tcx>, + ty: ty::Ty<'tcx>, + ) -> bool { + ty.ty_adt_def().map_or(false, |adt_def| adt_def.is_manually_drop()) + || ty.is_copy_modulo_regions(tcx.at(DUMMY_SP), param_env) + } + // Non-`Copy` fields are unstable, except for `ManuallyDrop`. let param_env = self.tcx.param_env(item.def_id); for field in &adt_def.non_enum_variant().fields { let field_ty = field.ty(self.tcx, substs); - if !field_ty.ty_adt_def().map_or(false, |adt_def| adt_def.is_manually_drop()) - && !field_ty.is_copy_modulo_regions(self.tcx.at(DUMMY_SP), param_env) - { + if !allowed_union_field(self.tcx, param_env, field_ty) { if field_ty.needs_drop(self.tcx, param_env) { // Avoid duplicate error: This will error later anyway because fields // that need drop are not allowed. From 55a1ccfef9633450722f22eccbf5925e91509320 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 10 Jun 2022 22:12:57 -0700 Subject: [PATCH 15/29] allow unions with mutable references and tuples of allowed types --- compiler/rustc_passes/src/stability.rs | 27 +++++++++++++++---- .../feature-gate-untagged_unions.rs | 22 +++++++++++++-- .../feature-gate-untagged_unions.stderr | 22 +++++++++++---- 3 files changed, 59 insertions(+), 12 deletions(-) diff --git a/compiler/rustc_passes/src/stability.rs b/compiler/rustc_passes/src/stability.rs index a1697978d66a3..187a3f95d5209 100644 --- a/compiler/rustc_passes/src/stability.rs +++ b/compiler/rustc_passes/src/stability.rs @@ -772,17 +772,27 @@ impl<'tcx> Visitor<'tcx> for Checker<'tcx> { let ty = self.tcx.type_of(item.def_id); let ty::Adt(adt_def, substs) = ty.kind() else { bug!() }; - #[allow(rustc::usage_of_qualified_ty)] // `Ty` is the wrong type here, we really want `ty::Ty`. + #[allow(rustc::usage_of_qualified_ty)] // `Ty` is `hir::Ty` here, we really want `ty::Ty`. fn allowed_union_field<'tcx>( tcx: TyCtxt<'tcx>, param_env: ty::ParamEnv<'tcx>, ty: ty::Ty<'tcx>, ) -> bool { - ty.ty_adt_def().map_or(false, |adt_def| adt_def.is_manually_drop()) - || ty.is_copy_modulo_regions(tcx.at(DUMMY_SP), param_env) + // We don't just accept all !needs_drop fields, due to semver concerns. + match ty.kind() { + ty::Ref(..) => true, // references never drop (even mutable refs, which are non-Copy and hence fail the later check) + ty::Tuple(tys) => { + // allow tuples of allowed types + tys.iter().all(|ty| allowed_union_field(tcx, param_env, ty)) + } + _ => { + ty.ty_adt_def().map_or(false, |adt_def| adt_def.is_manually_drop()) + || ty.is_copy_modulo_regions(tcx.at(DUMMY_SP), param_env) + } + } } - // Non-`Copy` fields are unstable, except for `ManuallyDrop`. + // `allowed_union_field` determines which fields are allowed on stable. let param_env = self.tcx.param_env(item.def_id); for field in &adt_def.non_enum_variant().fields { let field_ty = field.ty(self.tcx, substs); @@ -799,10 +809,17 @@ impl<'tcx> Visitor<'tcx> for Checker<'tcx> { &self.tcx.sess.parse_sess, sym::untagged_unions, self.tcx.def_span(field.did), - "unions with non-`Copy` fields other than `ManuallyDrop` are unstable", + "unions with non-`Copy` fields other than `ManuallyDrop`, \ + references, and tuples of such types are unstable", ) .emit(); } + } else { + // We allow this field. Make extra sure it does not drop. + assert!( + !field_ty.needs_drop(self.tcx, param_env), + "we should accept no maybe-dropping union fields" + ); } } } diff --git a/src/test/ui/feature-gates/feature-gate-untagged_unions.rs b/src/test/ui/feature-gates/feature-gate-untagged_unions.rs index af8d8e92b20bd..7bc5c42b77516 100644 --- a/src/test/ui/feature-gates/feature-gate-untagged_unions.rs +++ b/src/test/ui/feature-gates/feature-gate-untagged_unions.rs @@ -1,4 +1,5 @@ // ignore-tidy-linelength +use std::mem::ManuallyDrop; union U1 { // OK a: u8, @@ -9,7 +10,11 @@ union U2 { // OK } union U22 { // OK - a: std::mem::ManuallyDrop, + a: ManuallyDrop, +} + +union U23 { // OK + a: (ManuallyDrop, i32), } union U3 { @@ -17,7 +22,7 @@ union U3 { } union U32 { // field that does not drop but is not `Copy`, either -- this is the real feature gate test! - a: std::cell::RefCell, //~ ERROR unions with non-`Copy` fields other than `ManuallyDrop` are unstable + a: std::cell::RefCell, //~ ERROR unions with non-`Copy` fields other than `ManuallyDrop`, references, and tuples of such types are unstable } union U4 { @@ -32,4 +37,17 @@ impl Drop for U5 { fn drop(&mut self) {} } +union U5Nested { // a nested union that drops is NOT OK + nest: U5, //~ ERROR unions cannot contain fields that may need dropping +} + +union U6 { // OK + s: &'static i32, + m: &'static mut i32, +} + +union U7 { // OK + f: (&'static mut i32, ManuallyDrop, i32), +} + fn main() {} diff --git a/src/test/ui/feature-gates/feature-gate-untagged_unions.stderr b/src/test/ui/feature-gates/feature-gate-untagged_unions.stderr index 9e4a89f80c852..e1f10c6de333e 100644 --- a/src/test/ui/feature-gates/feature-gate-untagged_unions.stderr +++ b/src/test/ui/feature-gates/feature-gate-untagged_unions.stderr @@ -1,5 +1,5 @@ -error[E0658]: unions with non-`Copy` fields other than `ManuallyDrop` are unstable - --> $DIR/feature-gate-untagged_unions.rs:20:5 +error[E0658]: unions with non-`Copy` fields other than `ManuallyDrop`, references, and tuples of such types are unstable + --> $DIR/feature-gate-untagged_unions.rs:25:5 | LL | a: std::cell::RefCell, | ^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -8,7 +8,7 @@ LL | a: std::cell::RefCell, = help: add `#![feature(untagged_unions)]` to the crate attributes to enable error[E0740]: unions cannot contain fields that may need dropping - --> $DIR/feature-gate-untagged_unions.rs:16:5 + --> $DIR/feature-gate-untagged_unions.rs:21:5 | LL | a: String, | ^^^^^^^^^ @@ -20,7 +20,7 @@ LL | a: std::mem::ManuallyDrop, | +++++++++++++++++++++++ + error[E0740]: unions cannot contain fields that may need dropping - --> $DIR/feature-gate-untagged_unions.rs:24:5 + --> $DIR/feature-gate-untagged_unions.rs:29:5 | LL | a: T, | ^^^^ @@ -31,7 +31,19 @@ help: when the type does not implement `Copy`, wrap it inside a `ManuallyDrop<_> LL | a: std::mem::ManuallyDrop, | +++++++++++++++++++++++ + -error: aborting due to 3 previous errors +error[E0740]: unions cannot contain fields that may need dropping + --> $DIR/feature-gate-untagged_unions.rs:41:5 + | +LL | nest: U5, + | ^^^^^^^^ + | + = note: a type is guaranteed not to need dropping when it implements `Copy`, or when it is the special `ManuallyDrop<_>` type +help: when the type does not implement `Copy`, wrap it inside a `ManuallyDrop<_>` and ensure it is manually dropped + | +LL | nest: std::mem::ManuallyDrop, + | +++++++++++++++++++++++ + + +error: aborting due to 4 previous errors Some errors have detailed explanations: E0658, E0740. For more information about an error, try `rustc --explain E0658`. From cafbd738d48e0e75640c24f651b67789b72c0d0f Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 19 Jun 2022 09:57:07 -0700 Subject: [PATCH 16/29] also allow arrays of allowed types --- compiler/rustc_passes/src/stability.rs | 5 +++++ src/test/ui/feature-gates/feature-gate-untagged_unions.rs | 4 ++++ .../ui/feature-gates/feature-gate-untagged_unions.stderr | 8 ++++---- 3 files changed, 13 insertions(+), 4 deletions(-) diff --git a/compiler/rustc_passes/src/stability.rs b/compiler/rustc_passes/src/stability.rs index 187a3f95d5209..fa52c62b00cde 100644 --- a/compiler/rustc_passes/src/stability.rs +++ b/compiler/rustc_passes/src/stability.rs @@ -785,7 +785,12 @@ impl<'tcx> Visitor<'tcx> for Checker<'tcx> { // allow tuples of allowed types tys.iter().all(|ty| allowed_union_field(tcx, param_env, ty)) } + ty::Array(elem, _len) => { + // Like `Copy`, we do *not* special-case length 0. + allowed_union_field(tcx, param_env, *elem) + } _ => { + // Fallback case: allow `ManuallyDrop` and things that are `Copy`. ty.ty_adt_def().map_or(false, |adt_def| adt_def.is_manually_drop()) || ty.is_copy_modulo_regions(tcx.at(DUMMY_SP), param_env) } diff --git a/src/test/ui/feature-gates/feature-gate-untagged_unions.rs b/src/test/ui/feature-gates/feature-gate-untagged_unions.rs index 7bc5c42b77516..a3c05efe6667e 100644 --- a/src/test/ui/feature-gates/feature-gate-untagged_unions.rs +++ b/src/test/ui/feature-gates/feature-gate-untagged_unions.rs @@ -17,6 +17,10 @@ union U23 { // OK a: (ManuallyDrop, i32), } +union U24 { // OK + a: [ManuallyDrop; 2], +} + union U3 { a: String, //~ ERROR unions cannot contain fields that may need dropping } diff --git a/src/test/ui/feature-gates/feature-gate-untagged_unions.stderr b/src/test/ui/feature-gates/feature-gate-untagged_unions.stderr index e1f10c6de333e..038b85a60fc7b 100644 --- a/src/test/ui/feature-gates/feature-gate-untagged_unions.stderr +++ b/src/test/ui/feature-gates/feature-gate-untagged_unions.stderr @@ -1,5 +1,5 @@ error[E0658]: unions with non-`Copy` fields other than `ManuallyDrop`, references, and tuples of such types are unstable - --> $DIR/feature-gate-untagged_unions.rs:25:5 + --> $DIR/feature-gate-untagged_unions.rs:29:5 | LL | a: std::cell::RefCell, | ^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -8,7 +8,7 @@ LL | a: std::cell::RefCell, = help: add `#![feature(untagged_unions)]` to the crate attributes to enable error[E0740]: unions cannot contain fields that may need dropping - --> $DIR/feature-gate-untagged_unions.rs:21:5 + --> $DIR/feature-gate-untagged_unions.rs:25:5 | LL | a: String, | ^^^^^^^^^ @@ -20,7 +20,7 @@ LL | a: std::mem::ManuallyDrop, | +++++++++++++++++++++++ + error[E0740]: unions cannot contain fields that may need dropping - --> $DIR/feature-gate-untagged_unions.rs:29:5 + --> $DIR/feature-gate-untagged_unions.rs:33:5 | LL | a: T, | ^^^^ @@ -32,7 +32,7 @@ LL | a: std::mem::ManuallyDrop, | +++++++++++++++++++++++ + error[E0740]: unions cannot contain fields that may need dropping - --> $DIR/feature-gate-untagged_unions.rs:41:5 + --> $DIR/feature-gate-untagged_unions.rs:45:5 | LL | nest: U5, | ^^^^^^^^ From 14013964c35ae23cbf33ef85a600e120ae2ed56e Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 29 Jun 2022 22:33:18 -0400 Subject: [PATCH 17/29] remove untagged_union feature gate --- compiler/rustc_feature/src/active.rs | 7 -- compiler/rustc_feature/src/removed.rs | 3 + compiler/rustc_passes/src/stability.rs | 68 +------------------ compiler/rustc_typeck/src/check/check.rs | 35 +++++++++- .../ui/associated-type-bounds/duplicate.rs | 14 ++-- .../ui/associated-type-bounds/inside-adt.rs | 9 +-- .../associated-type-bounds/inside-adt.stderr | 64 ++++++++--------- .../ui/associated-type-bounds/union-bounds.rs | 1 - .../ui/binding/issue-53114-safety-checks.rs | 4 +- .../ui/borrowck/borrowck-union-move-assign.rs | 16 ++--- .../borrowck-union-move-assign.stderr | 2 +- src/test/ui/borrowck/borrowck-union-move.rs | 14 ++-- .../ui/borrowck/borrowck-union-move.stderr | 6 +- .../move-from-union-field-issue-66500.rs | 2 - .../move-from-union-field-issue-66500.stderr | 8 +-- src/test/ui/consts/invalid-union.64bit.stderr | 6 +- src/test/ui/consts/invalid-union.rs | 5 +- src/test/ui/consts/qualif-union.rs | 13 ++-- src/test/ui/consts/qualif-union.stderr | 10 +-- .../feature-gate-associated_type_bounds.rs | 8 +-- src/test/ui/nll/issue-55651.rs | 14 ++-- .../ui/repr/repr-packed-contains-align.rs | 5 +- .../ui/repr/repr-packed-contains-align.stderr | 40 +++++------ .../rfc-2093-infer-outlives/explicit-union.rs | 2 +- .../explicit-union.stderr | 2 +- .../rfc-2093-infer-outlives/nested-union.rs | 2 +- .../nested-union.stderr | 2 +- .../field_checks.rs} | 4 +- .../field_checks.stderr} | 30 ++++---- src/test/ui/union/issue-41073.rs | 2 - src/test/ui/union/issue-41073.stderr | 2 +- ...row-move-parent-sibling.mirunsafeck.stderr | 60 ++++++++++------ .../union/union-borrow-move-parent-sibling.rs | 28 ++++---- ...ow-move-parent-sibling.thirunsafeck.stderr | 60 ++++++++++------ src/test/ui/union/union-custom-drop.rs | 19 ------ src/test/ui/union/union-custom-drop.stderr | 15 ---- .../ui/union/union-deref.mirunsafeck.stderr | 12 ++-- src/test/ui/union/union-deref.rs | 1 - .../ui/union/union-deref.thirunsafeck.stderr | 12 ++-- .../ui/union/union-move.mirunsafeck.stderr | 2 +- src/test/ui/union/union-move.rs | 8 +-- .../ui/union/union-move.thirunsafeck.stderr | 2 +- src/test/ui/union/union-nonrepresentable.rs | 3 +- .../ui/union/union-nonrepresentable.stderr | 10 +-- src/test/ui/union/union-sized-field.rs | 8 +-- src/test/ui/union/union-sized-field.stderr | 33 +++++---- src/test/ui/union/union-unsafe.mir.stderr | 34 ++++------ src/test/ui/union/union-unsafe.rs | 7 +- src/test/ui/union/union-unsafe.thir.stderr | 34 ++++------ .../ui/union/union-unsized.mirunsafeck.stderr | 4 +- src/test/ui/union/union-unsized.rs | 2 - .../union/union-unsized.thirunsafeck.stderr | 4 +- .../unsafe/union-assignop.mirunsafeck.stderr | 28 +++----- src/test/ui/unsafe/union-assignop.rs | 15 ++-- .../unsafe/union-assignop.thirunsafeck.stderr | 28 +++----- src/test/ui/unsafe/union-modification.rs | 2 - src/test/ui/unsafe/union.rs | 4 +- 57 files changed, 386 insertions(+), 449 deletions(-) rename src/test/ui/{feature-gates/feature-gate-untagged_unions.rs => union/field_checks.rs} (82%) rename src/test/ui/{feature-gates/feature-gate-untagged_unions.stderr => union/field_checks.stderr} (69%) delete mode 100644 src/test/ui/union/union-custom-drop.rs delete mode 100644 src/test/ui/union/union-custom-drop.stderr diff --git a/compiler/rustc_feature/src/active.rs b/compiler/rustc_feature/src/active.rs index b54f0ef361a8d..2255b5e510660 100644 --- a/compiler/rustc_feature/src/active.rs +++ b/compiler/rustc_feature/src/active.rs @@ -528,13 +528,6 @@ declare_features! ( (incomplete, unsized_locals, "1.30.0", Some(48055), None), /// Allows unsized tuple coercion. (active, unsized_tuple_coercion, "1.20.0", Some(42877), None), - /// Allows `union`s to implement `Drop`. Moreover, `union`s may now include fields - /// that don't implement `Copy` as long as they don't have any drop glue. - /// This is checked recursively. On encountering type variable where no progress can be made, - /// `T: Copy` is used as a substitute for "no drop glue". - /// - /// NOTE: A limited form of `union U { ... }` was accepted in 1.19.0. - (active, untagged_unions, "1.13.0", Some(55149), None), /// Allows using the `#[used(linker)]` (or `#[used(compiler)]`) attribute. (active, used_with_arg, "1.60.0", Some(93798), None), /// Allows `extern "wasm" fn` diff --git a/compiler/rustc_feature/src/removed.rs b/compiler/rustc_feature/src/removed.rs index 54626caaf53ea..3b0f9a65e07f3 100644 --- a/compiler/rustc_feature/src/removed.rs +++ b/compiler/rustc_feature/src/removed.rs @@ -180,6 +180,9 @@ declare_features! ( /// Allows using items which are missing stability attributes (removed, unmarked_api, "1.0.0", None, None, None), (removed, unsafe_no_drop_flag, "1.0.0", None, None, None), + /// Allows `union` fields that don't implement `Copy` as long as they don't have any drop glue. + (removed, untagged_unions, "1.13.0", Some(55149), None, + Some("unions with `Copy` and `MaybeUninit` fields are stable; there is no intent to stabilize more")), /// Allows `#[unwind(..)]`. /// /// Permits specifying whether a function should permit unwinding or abort on unwind. diff --git a/compiler/rustc_passes/src/stability.rs b/compiler/rustc_passes/src/stability.rs index fa52c62b00cde..a06213ca5f442 100644 --- a/compiler/rustc_passes/src/stability.rs +++ b/compiler/rustc_passes/src/stability.rs @@ -13,13 +13,12 @@ use rustc_hir::{FieldDef, Generics, HirId, Item, ItemKind, TraitRef, Ty, TyKind, use rustc_middle::hir::nested_filter; use rustc_middle::middle::privacy::AccessLevels; use rustc_middle::middle::stability::{AllowUnstable, DeprecationEntry, Index}; -use rustc_middle::ty::{self, query::Providers, TyCtxt}; +use rustc_middle::ty::{query::Providers, TyCtxt}; use rustc_session::lint; use rustc_session::lint::builtin::{INEFFECTIVE_UNSTABLE_TRAIT_IMPL, USELESS_DEPRECATED}; -use rustc_session::parse::feature_err; use rustc_session::Session; use rustc_span::symbol::{sym, Symbol}; -use rustc_span::{Span, DUMMY_SP}; +use rustc_span::Span; use rustc_target::spec::abi::Abi; use std::cmp::Ordering; @@ -766,69 +765,6 @@ impl<'tcx> Visitor<'tcx> for Checker<'tcx> { } } - // There's no good place to insert stability check for non-Copy unions, - // so semi-randomly perform it here in stability.rs - hir::ItemKind::Union(..) if !self.tcx.features().untagged_unions => { - let ty = self.tcx.type_of(item.def_id); - let ty::Adt(adt_def, substs) = ty.kind() else { bug!() }; - - #[allow(rustc::usage_of_qualified_ty)] // `Ty` is `hir::Ty` here, we really want `ty::Ty`. - fn allowed_union_field<'tcx>( - tcx: TyCtxt<'tcx>, - param_env: ty::ParamEnv<'tcx>, - ty: ty::Ty<'tcx>, - ) -> bool { - // We don't just accept all !needs_drop fields, due to semver concerns. - match ty.kind() { - ty::Ref(..) => true, // references never drop (even mutable refs, which are non-Copy and hence fail the later check) - ty::Tuple(tys) => { - // allow tuples of allowed types - tys.iter().all(|ty| allowed_union_field(tcx, param_env, ty)) - } - ty::Array(elem, _len) => { - // Like `Copy`, we do *not* special-case length 0. - allowed_union_field(tcx, param_env, *elem) - } - _ => { - // Fallback case: allow `ManuallyDrop` and things that are `Copy`. - ty.ty_adt_def().map_or(false, |adt_def| adt_def.is_manually_drop()) - || ty.is_copy_modulo_regions(tcx.at(DUMMY_SP), param_env) - } - } - } - - // `allowed_union_field` determines which fields are allowed on stable. - let param_env = self.tcx.param_env(item.def_id); - for field in &adt_def.non_enum_variant().fields { - let field_ty = field.ty(self.tcx, substs); - if !allowed_union_field(self.tcx, param_env, field_ty) { - if field_ty.needs_drop(self.tcx, param_env) { - // Avoid duplicate error: This will error later anyway because fields - // that need drop are not allowed. - self.tcx.sess.delay_span_bug( - item.span, - "union should have been rejected due to potentially dropping field", - ); - } else { - feature_err( - &self.tcx.sess.parse_sess, - sym::untagged_unions, - self.tcx.def_span(field.did), - "unions with non-`Copy` fields other than `ManuallyDrop`, \ - references, and tuples of such types are unstable", - ) - .emit(); - } - } else { - // We allow this field. Make extra sure it does not drop. - assert!( - !field_ty.needs_drop(self.tcx, param_env), - "we should accept no maybe-dropping union fields" - ); - } - } - } - _ => (/* pass */), } intravisit::walk_item(self, item); diff --git a/compiler/rustc_typeck/src/check/check.rs b/compiler/rustc_typeck/src/check/check.rs index e9709b64d930e..209842f658540 100644 --- a/compiler/rustc_typeck/src/check/check.rs +++ b/compiler/rustc_typeck/src/check/check.rs @@ -401,11 +401,37 @@ fn check_union_fields(tcx: TyCtxt<'_>, span: Span, item_def_id: LocalDefId) -> b let item_type = tcx.type_of(item_def_id); if let ty::Adt(def, substs) = item_type.kind() { assert!(def.is_union()); - let fields = &def.non_enum_variant().fields; + + fn allowed_union_field<'tcx>( + ty: Ty<'tcx>, + tcx: TyCtxt<'tcx>, + param_env: ty::ParamEnv<'tcx>, + span: Span, + ) -> bool { + // We don't just accept all !needs_drop fields, due to semver concerns. + match ty.kind() { + ty::Ref(..) => true, // references never drop (even mutable refs, which are non-Copy and hence fail the later check) + ty::Tuple(tys) => { + // allow tuples of allowed types + tys.iter().all(|ty| allowed_union_field(ty, tcx, param_env, span)) + } + ty::Array(elem, _len) => { + // Like `Copy`, we do *not* special-case length 0. + allowed_union_field(*elem, tcx, param_env, span) + } + _ => { + // Fallback case: allow `ManuallyDrop` and things that are `Copy`. + ty.ty_adt_def().map_or(false, |adt_def| adt_def.is_manually_drop()) + || ty.is_copy_modulo_regions(tcx.at(span), param_env) + } + } + } + let param_env = tcx.param_env(item_def_id); - for field in fields { + for field in &def.non_enum_variant().fields { let field_ty = field.ty(tcx, substs); - if field_ty.needs_drop(tcx, param_env) { + + if !allowed_union_field(field_ty, tcx, param_env, span) { let (field_span, ty_span) = match tcx.hir().get_if_local(field.did) { // We are currently checking the type this field came from, so it must be local. Some(Node::Field(field)) => (field.span, field.ty.span), @@ -432,6 +458,9 @@ fn check_union_fields(tcx: TyCtxt<'_>, span: Span, item_def_id: LocalDefId) -> b ) .emit(); return false; + } else if field_ty.needs_drop(tcx, param_env) { + // This should never happen. But we can get here e.g. in case of name resolution errors. + tcx.sess.delay_span_bug(span, "we should never accept maybe-dropping union fields"); } } } else { diff --git a/src/test/ui/associated-type-bounds/duplicate.rs b/src/test/ui/associated-type-bounds/duplicate.rs index e1dc6f8f4b63d..6e464f69510ec 100644 --- a/src/test/ui/associated-type-bounds/duplicate.rs +++ b/src/test/ui/associated-type-bounds/duplicate.rs @@ -1,8 +1,8 @@ #![feature(associated_type_bounds)] #![feature(type_alias_impl_trait)] -#![feature(untagged_unions)] use std::iter; +use std::mem::ManuallyDrop; struct SI1> { //~^ ERROR the value of the associated type `Item` (from trait `Iterator`) is already specified [E0719] @@ -74,36 +74,36 @@ where union UI1> { //~^ ERROR the value of the associated type `Item` (from trait `Iterator`) is already specified [E0719] - f: T, + f: ManuallyDrop, } union UI2> { //~^ ERROR the value of the associated type `Item` (from trait `Iterator`) is already specified [E0719] - f: T, + f: ManuallyDrop, } union UI3> { //~^ ERROR the value of the associated type `Item` (from trait `Iterator`) is already specified [E0719] - f: T, + f: ManuallyDrop, } union UW1 where T: Iterator, //~^ ERROR the value of the associated type `Item` (from trait `Iterator`) is already specified [E0719] { - f: T, + f: ManuallyDrop, } union UW2 where T: Iterator, //~^ ERROR the value of the associated type `Item` (from trait `Iterator`) is already specified [E0719] { - f: T, + f: ManuallyDrop, } union UW3 where T: Iterator, //~^ ERROR the value of the associated type `Item` (from trait `Iterator`) is already specified [E0719] { - f: T, + f: ManuallyDrop, } fn FI1>() {} diff --git a/src/test/ui/associated-type-bounds/inside-adt.rs b/src/test/ui/associated-type-bounds/inside-adt.rs index 5af057387509d..f26037f070766 100644 --- a/src/test/ui/associated-type-bounds/inside-adt.rs +++ b/src/test/ui/associated-type-bounds/inside-adt.rs @@ -1,5 +1,6 @@ #![feature(associated_type_bounds)] -#![feature(untagged_unions)] + +use std::mem::ManuallyDrop; struct S1 { f: dyn Iterator } //~^ ERROR associated type bounds are not allowed within structs, enums, or unions @@ -17,12 +18,12 @@ enum E3 { V(dyn Iterator) } //~^ ERROR associated type bounds are not allowed within structs, enums, or unions //~| ERROR the size for values of type `(dyn Iterator + 'static)` -union U1 { f: dyn Iterator } +union U1 { f: ManuallyDrop> } //~^ ERROR associated type bounds are not allowed within structs, enums, or unions //~| ERROR the size for values of type `(dyn Iterator + 'static)` -union U2 { f: Box> } +union U2 { f: ManuallyDrop>> } //~^ ERROR associated type bounds are not allowed within structs, enums, or unions -union U3 { f: dyn Iterator } +union U3 { f: ManuallyDrop> } //~^ ERROR associated type bounds are not allowed within structs, enums, or unions //~| ERROR the size for values of type `(dyn Iterator + 'static)` diff --git a/src/test/ui/associated-type-bounds/inside-adt.stderr b/src/test/ui/associated-type-bounds/inside-adt.stderr index 0cacd78724732..978390fa71235 100644 --- a/src/test/ui/associated-type-bounds/inside-adt.stderr +++ b/src/test/ui/associated-type-bounds/inside-adt.stderr @@ -1,59 +1,59 @@ error: associated type bounds are not allowed within structs, enums, or unions - --> $DIR/inside-adt.rs:4:29 + --> $DIR/inside-adt.rs:5:29 | LL | struct S1 { f: dyn Iterator } | ^^^^^^^^^^ error: associated type bounds are not allowed within structs, enums, or unions - --> $DIR/inside-adt.rs:6:33 + --> $DIR/inside-adt.rs:7:33 | LL | struct S2 { f: Box> } | ^^^^^^^^^^ error: associated type bounds are not allowed within structs, enums, or unions - --> $DIR/inside-adt.rs:8:29 + --> $DIR/inside-adt.rs:9:29 | LL | struct S3 { f: dyn Iterator } | ^^^^^^^^^^^^^ error: associated type bounds are not allowed within structs, enums, or unions - --> $DIR/inside-adt.rs:11:26 + --> $DIR/inside-adt.rs:12:26 | LL | enum E1 { V(dyn Iterator) } | ^^^^^^^^^^ error: associated type bounds are not allowed within structs, enums, or unions - --> $DIR/inside-adt.rs:14:30 + --> $DIR/inside-adt.rs:15:30 | LL | enum E2 { V(Box>) } | ^^^^^^^^^^ error: associated type bounds are not allowed within structs, enums, or unions - --> $DIR/inside-adt.rs:16:26 + --> $DIR/inside-adt.rs:17:26 | LL | enum E3 { V(dyn Iterator) } | ^^^^^^^^^^^^^ error: associated type bounds are not allowed within structs, enums, or unions - --> $DIR/inside-adt.rs:20:28 + --> $DIR/inside-adt.rs:21:41 | -LL | union U1 { f: dyn Iterator } - | ^^^^^^^^^^ +LL | union U1 { f: ManuallyDrop> } + | ^^^^^^^^^^ error: associated type bounds are not allowed within structs, enums, or unions - --> $DIR/inside-adt.rs:23:32 + --> $DIR/inside-adt.rs:24:45 | -LL | union U2 { f: Box> } - | ^^^^^^^^^^ +LL | union U2 { f: ManuallyDrop>> } + | ^^^^^^^^^^ error: associated type bounds are not allowed within structs, enums, or unions - --> $DIR/inside-adt.rs:25:28 + --> $DIR/inside-adt.rs:26:41 | -LL | union U3 { f: dyn Iterator } - | ^^^^^^^^^^^^^ +LL | union U3 { f: ManuallyDrop> } + | ^^^^^^^^^^^^^ error[E0277]: the size for values of type `(dyn Iterator + 'static)` cannot be known at compilation time - --> $DIR/inside-adt.rs:11:13 + --> $DIR/inside-adt.rs:12:13 | LL | enum E1 { V(dyn Iterator) } | ^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time @@ -71,7 +71,7 @@ LL | enum E1 { V(Box>) } | ++++ + error[E0277]: the size for values of type `(dyn Iterator + 'static)` cannot be known at compilation time - --> $DIR/inside-adt.rs:16:13 + --> $DIR/inside-adt.rs:17:13 | LL | enum E3 { V(dyn Iterator) } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time @@ -89,40 +89,42 @@ LL | enum E3 { V(Box>) } | ++++ + error[E0277]: the size for values of type `(dyn Iterator + 'static)` cannot be known at compilation time - --> $DIR/inside-adt.rs:20:15 + --> $DIR/inside-adt.rs:21:15 | -LL | union U1 { f: dyn Iterator } - | ^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time +LL | union U1 { f: ManuallyDrop> } + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time | - = help: the trait `Sized` is not implemented for `(dyn Iterator + 'static)` + = help: within `ManuallyDrop<(dyn Iterator + 'static)>`, the trait `Sized` is not implemented for `(dyn Iterator + 'static)` + = note: required because it appears within the type `ManuallyDrop<(dyn Iterator + 'static)>` = note: no field of a union may have a dynamically sized type = help: change the field's type to have a statically known size help: borrowed types always have a statically known size | -LL | union U1 { f: &dyn Iterator } +LL | union U1 { f: &ManuallyDrop> } | + help: the `Box` type always has a statically known size and allocates its contents in the heap | -LL | union U1 { f: Box> } - | ++++ + +LL | union U1 { f: Box>> } + | ++++ + error[E0277]: the size for values of type `(dyn Iterator + 'static)` cannot be known at compilation time - --> $DIR/inside-adt.rs:25:15 + --> $DIR/inside-adt.rs:26:15 | -LL | union U3 { f: dyn Iterator } - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time +LL | union U3 { f: ManuallyDrop> } + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time | - = help: the trait `Sized` is not implemented for `(dyn Iterator + 'static)` + = help: within `ManuallyDrop<(dyn Iterator + 'static)>`, the trait `Sized` is not implemented for `(dyn Iterator + 'static)` + = note: required because it appears within the type `ManuallyDrop<(dyn Iterator + 'static)>` = note: no field of a union may have a dynamically sized type = help: change the field's type to have a statically known size help: borrowed types always have a statically known size | -LL | union U3 { f: &dyn Iterator } +LL | union U3 { f: &ManuallyDrop> } | + help: the `Box` type always has a statically known size and allocates its contents in the heap | -LL | union U3 { f: Box> } - | ++++ + +LL | union U3 { f: Box>> } + | ++++ + error: aborting due to 13 previous errors diff --git a/src/test/ui/associated-type-bounds/union-bounds.rs b/src/test/ui/associated-type-bounds/union-bounds.rs index 97c5acf1f72ca..46e5aef04031a 100644 --- a/src/test/ui/associated-type-bounds/union-bounds.rs +++ b/src/test/ui/associated-type-bounds/union-bounds.rs @@ -1,7 +1,6 @@ // run-pass #![feature(associated_type_bounds)] -#![feature(untagged_unions)] #![allow(unused_assignments)] diff --git a/src/test/ui/binding/issue-53114-safety-checks.rs b/src/test/ui/binding/issue-53114-safety-checks.rs index 5042ad024afff..d0eb28c571411 100644 --- a/src/test/ui/binding/issue-53114-safety-checks.rs +++ b/src/test/ui/binding/issue-53114-safety-checks.rs @@ -3,9 +3,9 @@ // captures the behavior of how `_` bindings are handled with respect to how we // flag expressions that are meant to request unsafe blocks. -#![feature(untagged_unions)] - +#[derive(Copy, Clone)] struct I(i64); +#[derive(Copy, Clone)] struct F(f64); union U { a: I, b: F } diff --git a/src/test/ui/borrowck/borrowck-union-move-assign.rs b/src/test/ui/borrowck/borrowck-union-move-assign.rs index a24f42d2ddf87..4c96ccdb25aaa 100644 --- a/src/test/ui/borrowck/borrowck-union-move-assign.rs +++ b/src/test/ui/borrowck/borrowck-union-move-assign.rs @@ -1,31 +1,31 @@ -#![feature(untagged_unions)] +use std::mem::ManuallyDrop; // Non-copy struct A; struct B; union U { - a: A, - b: B, + a: ManuallyDrop, + b: ManuallyDrop, } fn main() { unsafe { { - let mut u = U { a: A }; + let mut u = U { a: ManuallyDrop::new(A) }; let a = u.a; let a = u.a; //~ ERROR use of moved value: `u` } { - let mut u = U { a: A }; + let mut u = U { a: ManuallyDrop::new(A) }; let a = u.a; - u.a = A; + u.a = ManuallyDrop::new(A); let a = u.a; // OK } { - let mut u = U { a: A }; + let mut u = U { a: ManuallyDrop::new(A) }; let a = u.a; - u.b = B; + u.b = ManuallyDrop::new(B); let a = u.a; // OK } } diff --git a/src/test/ui/borrowck/borrowck-union-move-assign.stderr b/src/test/ui/borrowck/borrowck-union-move-assign.stderr index 0b1714fd75dc0..af6f6fac40870 100644 --- a/src/test/ui/borrowck/borrowck-union-move-assign.stderr +++ b/src/test/ui/borrowck/borrowck-union-move-assign.stderr @@ -1,7 +1,7 @@ error[E0382]: use of moved value: `u` --> $DIR/borrowck-union-move-assign.rs:17:21 | -LL | let mut u = U { a: A }; +LL | let mut u = U { a: ManuallyDrop::new(A) }; | ----- move occurs because `u` has type `U`, which does not implement the `Copy` trait LL | let a = u.a; | --- value moved here diff --git a/src/test/ui/borrowck/borrowck-union-move.rs b/src/test/ui/borrowck/borrowck-union-move.rs index d0aa6dff74410..510547ad5bb74 100644 --- a/src/test/ui/borrowck/borrowck-union-move.rs +++ b/src/test/ui/borrowck/borrowck-union-move.rs @@ -1,12 +1,12 @@ -#![feature(untagged_unions)] +use std::mem::ManuallyDrop; #[derive(Clone, Copy)] struct Copy; struct NonCopy; union Unn { - n1: NonCopy, - n2: NonCopy, + n1: ManuallyDrop, + n2: ManuallyDrop, } union Ucc { c1: Copy, @@ -14,24 +14,24 @@ union Ucc { } union Ucn { c: Copy, - n: NonCopy, + n: ManuallyDrop, } fn main() { unsafe { // 2 NonCopy { - let mut u = Unn { n1: NonCopy }; + let mut u = Unn { n1: ManuallyDrop::new(NonCopy) }; let a = u.n1; let a = u.n1; //~ ERROR use of moved value: `u` } { - let mut u = Unn { n1: NonCopy }; + let mut u = Unn { n1: ManuallyDrop::new(NonCopy) }; let a = u.n1; let a = u; //~ ERROR use of moved value: `u` } { - let mut u = Unn { n1: NonCopy }; + let mut u = Unn { n1: ManuallyDrop::new(NonCopy) }; let a = u.n1; let a = u.n2; //~ ERROR use of moved value: `u` } diff --git a/src/test/ui/borrowck/borrowck-union-move.stderr b/src/test/ui/borrowck/borrowck-union-move.stderr index abbb0142a9c30..731607fbdd1f7 100644 --- a/src/test/ui/borrowck/borrowck-union-move.stderr +++ b/src/test/ui/borrowck/borrowck-union-move.stderr @@ -1,7 +1,7 @@ error[E0382]: use of moved value: `u` --> $DIR/borrowck-union-move.rs:26:21 | -LL | let mut u = Unn { n1: NonCopy }; +LL | let mut u = Unn { n1: ManuallyDrop::new(NonCopy) }; | ----- move occurs because `u` has type `Unn`, which does not implement the `Copy` trait LL | let a = u.n1; | ---- value moved here @@ -11,7 +11,7 @@ LL | let a = u.n1; error[E0382]: use of moved value: `u` --> $DIR/borrowck-union-move.rs:31:21 | -LL | let mut u = Unn { n1: NonCopy }; +LL | let mut u = Unn { n1: ManuallyDrop::new(NonCopy) }; | ----- move occurs because `u` has type `Unn`, which does not implement the `Copy` trait LL | let a = u.n1; | ---- value moved here @@ -21,7 +21,7 @@ LL | let a = u; error[E0382]: use of moved value: `u` --> $DIR/borrowck-union-move.rs:36:21 | -LL | let mut u = Unn { n1: NonCopy }; +LL | let mut u = Unn { n1: ManuallyDrop::new(NonCopy) }; | ----- move occurs because `u` has type `Unn`, which does not implement the `Copy` trait LL | let a = u.n1; | ---- value moved here diff --git a/src/test/ui/borrowck/move-from-union-field-issue-66500.rs b/src/test/ui/borrowck/move-from-union-field-issue-66500.rs index 8fbf120fc1c78..0bd2147f46331 100644 --- a/src/test/ui/borrowck/move-from-union-field-issue-66500.rs +++ b/src/test/ui/borrowck/move-from-union-field-issue-66500.rs @@ -1,8 +1,6 @@ // Moving from a reference/raw pointer should be an error, even when they're // the field of a union. -#![feature(untagged_unions)] - union Pointers { a: &'static String, b: &'static mut String, diff --git a/src/test/ui/borrowck/move-from-union-field-issue-66500.stderr b/src/test/ui/borrowck/move-from-union-field-issue-66500.stderr index 82c3fe3b12d1c..70078582713c6 100644 --- a/src/test/ui/borrowck/move-from-union-field-issue-66500.stderr +++ b/src/test/ui/borrowck/move-from-union-field-issue-66500.stderr @@ -1,23 +1,23 @@ error[E0507]: cannot move out of `*u.a` which is behind a shared reference - --> $DIR/move-from-union-field-issue-66500.rs:14:5 + --> $DIR/move-from-union-field-issue-66500.rs:12:5 | LL | *u.a | ^^^^ move occurs because `*u.a` has type `String`, which does not implement the `Copy` trait error[E0507]: cannot move out of `*u.b` which is behind a mutable reference - --> $DIR/move-from-union-field-issue-66500.rs:18:5 + --> $DIR/move-from-union-field-issue-66500.rs:16:5 | LL | *u.b | ^^^^ move occurs because `*u.b` has type `String`, which does not implement the `Copy` trait error[E0507]: cannot move out of `*u.c` which is behind a raw pointer - --> $DIR/move-from-union-field-issue-66500.rs:22:5 + --> $DIR/move-from-union-field-issue-66500.rs:20:5 | LL | *u.c | ^^^^ move occurs because `*u.c` has type `String`, which does not implement the `Copy` trait error[E0507]: cannot move out of `*u.d` which is behind a raw pointer - --> $DIR/move-from-union-field-issue-66500.rs:26:5 + --> $DIR/move-from-union-field-issue-66500.rs:24:5 | LL | *u.d | ^^^^ move occurs because `*u.d` has type `String`, which does not implement the `Copy` trait diff --git a/src/test/ui/consts/invalid-union.64bit.stderr b/src/test/ui/consts/invalid-union.64bit.stderr index 81c1024424972..d50e74a16ec36 100644 --- a/src/test/ui/consts/invalid-union.64bit.stderr +++ b/src/test/ui/consts/invalid-union.64bit.stderr @@ -1,5 +1,5 @@ error[E0080]: it is undefined behavior to use this value - --> $DIR/invalid-union.rs:40:1 + --> $DIR/invalid-union.rs:41:1 | LL | fn main() { | ^^^^^^^^^ constructing invalid value at ..y..0: encountered `UnsafeCell` in a `const` @@ -10,7 +10,7 @@ LL | fn main() { } error: erroneous constant used - --> $DIR/invalid-union.rs:41:25 + --> $DIR/invalid-union.rs:42:25 | LL | let _: &'static _ = &C; | ^^ referenced constant has errors @@ -24,7 +24,7 @@ error: aborting due to 2 previous errors For more information about this error, try `rustc --explain E0080`. Future incompatibility report: Future breakage diagnostic: error: erroneous constant used - --> $DIR/invalid-union.rs:41:25 + --> $DIR/invalid-union.rs:42:25 | LL | let _: &'static _ = &C; | ^^ referenced constant has errors diff --git a/src/test/ui/consts/invalid-union.rs b/src/test/ui/consts/invalid-union.rs index f3f1af89b2c41..efeddf75cb557 100644 --- a/src/test/ui/consts/invalid-union.rs +++ b/src/test/ui/consts/invalid-union.rs @@ -9,8 +9,9 @@ // build-fail // stderr-per-bitwidth #![feature(const_mut_refs)] -#![feature(untagged_unions)] + use std::cell::Cell; +use std::mem::ManuallyDrop; #[repr(C)] struct S { @@ -25,7 +26,7 @@ enum E { } union U { - cell: Cell, + cell: ManuallyDrop>, } const C: S = { diff --git a/src/test/ui/consts/qualif-union.rs b/src/test/ui/consts/qualif-union.rs index 2054b5b89ed6e..11c019be96432 100644 --- a/src/test/ui/consts/qualif-union.rs +++ b/src/test/ui/consts/qualif-union.rs @@ -1,18 +1,19 @@ // Checks that unions use type based qualification. Regression test for issue #90268. -#![feature(untagged_unions)] + use std::cell::Cell; +use std::mem::ManuallyDrop; -union U { i: u32, c: Cell } +union U { i: u32, c: ManuallyDrop> } -const C1: Cell = { - unsafe { U { c: Cell::new(0) }.c } +const C1: ManuallyDrop> = { + unsafe { U { c: ManuallyDrop::new(Cell::new(0)) }.c } }; -const C2: Cell = { +const C2: ManuallyDrop> = { unsafe { U { i : 0 }.c } }; -const C3: Cell = { +const C3: ManuallyDrop> = { let mut u = U { i: 0 }; u.i = 1; unsafe { u.c } diff --git a/src/test/ui/consts/qualif-union.stderr b/src/test/ui/consts/qualif-union.stderr index fda8ad4a3bc81..8ec68ada048a5 100644 --- a/src/test/ui/consts/qualif-union.stderr +++ b/src/test/ui/consts/qualif-union.stderr @@ -1,5 +1,5 @@ error[E0716]: temporary value dropped while borrowed - --> $DIR/qualif-union.rs:27:26 + --> $DIR/qualif-union.rs:28:26 | LL | let _: &'static _ = &C1; | ---------- ^^ creates a temporary which is freed while still in use @@ -10,7 +10,7 @@ LL | } | - temporary value is freed at the end of this statement error[E0716]: temporary value dropped while borrowed - --> $DIR/qualif-union.rs:28:26 + --> $DIR/qualif-union.rs:29:26 | LL | let _: &'static _ = &C2; | ---------- ^^ creates a temporary which is freed while still in use @@ -21,7 +21,7 @@ LL | } | - temporary value is freed at the end of this statement error[E0716]: temporary value dropped while borrowed - --> $DIR/qualif-union.rs:29:26 + --> $DIR/qualif-union.rs:30:26 | LL | let _: &'static _ = &C3; | ---------- ^^ creates a temporary which is freed while still in use @@ -32,7 +32,7 @@ LL | } | - temporary value is freed at the end of this statement error[E0716]: temporary value dropped while borrowed - --> $DIR/qualif-union.rs:30:26 + --> $DIR/qualif-union.rs:31:26 | LL | let _: &'static _ = &C4; | ---------- ^^ creates a temporary which is freed while still in use @@ -43,7 +43,7 @@ LL | } | - temporary value is freed at the end of this statement error[E0716]: temporary value dropped while borrowed - --> $DIR/qualif-union.rs:31:26 + --> $DIR/qualif-union.rs:32:26 | LL | let _: &'static _ = &C5; | ---------- ^^ creates a temporary which is freed while still in use diff --git a/src/test/ui/feature-gates/feature-gate-associated_type_bounds.rs b/src/test/ui/feature-gates/feature-gate-associated_type_bounds.rs index a93fb7977131d..4e020327447ff 100644 --- a/src/test/ui/feature-gates/feature-gate-associated_type_bounds.rs +++ b/src/test/ui/feature-gates/feature-gate-associated_type_bounds.rs @@ -1,7 +1,7 @@ // compile-flags: -Zsave-analysis // This is also a regression test for #69415 and the above flag is needed. -#![feature(untagged_unions)] +use std::mem::ManuallyDrop; trait Tr1 { type As1: Copy; } trait Tr2 { type As2: Copy; } @@ -36,9 +36,9 @@ enum _En1> { union _Un1> { //~^ ERROR associated type bounds are unstable - outest: std::mem::ManuallyDrop, - outer: T::As1, - inner: ::As2, + outest: ManuallyDrop, + outer: ManuallyDrop, + inner: ManuallyDrop<::As2>, } type _TaWhere1 where T: Iterator = T; diff --git a/src/test/ui/nll/issue-55651.rs b/src/test/ui/nll/issue-55651.rs index 46255bf74a138..75ba482717460 100644 --- a/src/test/ui/nll/issue-55651.rs +++ b/src/test/ui/nll/issue-55651.rs @@ -1,27 +1,27 @@ // check-pass -#![feature(untagged_unions)] +use std::mem::ManuallyDrop; struct A; struct B; union U { - a: A, - b: B, + a: ManuallyDrop, + b: ManuallyDrop, } fn main() { unsafe { { - let mut u = U { a: A }; + let mut u = U { a: ManuallyDrop::new(A) }; let a = u.a; - u.a = A; + u.a = ManuallyDrop::new(A); let a = u.a; // OK } { - let mut u = U { a: A }; + let mut u = U { a: ManuallyDrop::new(A) }; let a = u.a; - u.b = B; + u.b = ManuallyDrop::new(B); let a = u.a; // OK } } diff --git a/src/test/ui/repr/repr-packed-contains-align.rs b/src/test/ui/repr/repr-packed-contains-align.rs index 67d87eb5cd520..bef5c7d8c62fc 100644 --- a/src/test/ui/repr/repr-packed-contains-align.rs +++ b/src/test/ui/repr/repr-packed-contains-align.rs @@ -1,16 +1,19 @@ -#![feature(untagged_unions)] #![allow(dead_code)] #[repr(align(16))] +#[derive(Clone, Copy)] struct SA(i32); +#[derive(Clone, Copy)] struct SB(SA); #[repr(align(16))] +#[derive(Clone, Copy)] union UA { i: i32 } +#[derive(Clone, Copy)] union UB { a: UA } diff --git a/src/test/ui/repr/repr-packed-contains-align.stderr b/src/test/ui/repr/repr-packed-contains-align.stderr index 531004e8e202b..4c3a960cad2a6 100644 --- a/src/test/ui/repr/repr-packed-contains-align.stderr +++ b/src/test/ui/repr/repr-packed-contains-align.stderr @@ -1,5 +1,5 @@ error[E0588]: packed type cannot transitively contain a `#[repr(align)]` type - --> $DIR/repr-packed-contains-align.rs:19:1 + --> $DIR/repr-packed-contains-align.rs:22:1 | LL | struct SC(SA); | ^^^^^^^^^ @@ -11,7 +11,7 @@ LL | struct SA(i32); | ^^^^^^^^^ error[E0588]: packed type cannot transitively contain a `#[repr(align)]` type - --> $DIR/repr-packed-contains-align.rs:22:1 + --> $DIR/repr-packed-contains-align.rs:25:1 | LL | struct SD(SB); | ^^^^^^^^^ @@ -22,86 +22,86 @@ note: `SA` has a `#[repr(align)]` attribute LL | struct SA(i32); | ^^^^^^^^^ note: `SD` contains a field of type `SB` - --> $DIR/repr-packed-contains-align.rs:22:11 + --> $DIR/repr-packed-contains-align.rs:25:11 | LL | struct SD(SB); | ^^ note: ...which contains a field of type `SA` - --> $DIR/repr-packed-contains-align.rs:7:11 + --> $DIR/repr-packed-contains-align.rs:8:11 | LL | struct SB(SA); | ^^ error[E0588]: packed type cannot transitively contain a `#[repr(align)]` type - --> $DIR/repr-packed-contains-align.rs:25:1 + --> $DIR/repr-packed-contains-align.rs:28:1 | LL | struct SE(UA); | ^^^^^^^^^ | note: `UA` has a `#[repr(align)]` attribute - --> $DIR/repr-packed-contains-align.rs:10:1 + --> $DIR/repr-packed-contains-align.rs:12:1 | LL | union UA { | ^^^^^^^^ error[E0588]: packed type cannot transitively contain a `#[repr(align)]` type - --> $DIR/repr-packed-contains-align.rs:28:1 + --> $DIR/repr-packed-contains-align.rs:31:1 | LL | struct SF(UB); | ^^^^^^^^^ | note: `UA` has a `#[repr(align)]` attribute - --> $DIR/repr-packed-contains-align.rs:10:1 + --> $DIR/repr-packed-contains-align.rs:12:1 | LL | union UA { | ^^^^^^^^ note: `SF` contains a field of type `UB` - --> $DIR/repr-packed-contains-align.rs:28:11 + --> $DIR/repr-packed-contains-align.rs:31:11 | LL | struct SF(UB); | ^^ note: ...which contains a field of type `UA` - --> $DIR/repr-packed-contains-align.rs:15:5 + --> $DIR/repr-packed-contains-align.rs:18:5 | LL | a: UA | ^ error[E0588]: packed type cannot transitively contain a `#[repr(align)]` type - --> $DIR/repr-packed-contains-align.rs:31:1 + --> $DIR/repr-packed-contains-align.rs:34:1 | LL | union UC { | ^^^^^^^^ | note: `UA` has a `#[repr(align)]` attribute - --> $DIR/repr-packed-contains-align.rs:10:1 + --> $DIR/repr-packed-contains-align.rs:12:1 | LL | union UA { | ^^^^^^^^ error[E0588]: packed type cannot transitively contain a `#[repr(align)]` type - --> $DIR/repr-packed-contains-align.rs:36:1 + --> $DIR/repr-packed-contains-align.rs:39:1 | LL | union UD { | ^^^^^^^^ | note: `UA` has a `#[repr(align)]` attribute - --> $DIR/repr-packed-contains-align.rs:10:1 + --> $DIR/repr-packed-contains-align.rs:12:1 | LL | union UA { | ^^^^^^^^ note: `UD` contains a field of type `UB` - --> $DIR/repr-packed-contains-align.rs:37:5 + --> $DIR/repr-packed-contains-align.rs:40:5 | LL | n: UB | ^ note: ...which contains a field of type `UA` - --> $DIR/repr-packed-contains-align.rs:15:5 + --> $DIR/repr-packed-contains-align.rs:18:5 | LL | a: UA | ^ error[E0588]: packed type cannot transitively contain a `#[repr(align)]` type - --> $DIR/repr-packed-contains-align.rs:41:1 + --> $DIR/repr-packed-contains-align.rs:44:1 | LL | union UE { | ^^^^^^^^ @@ -113,7 +113,7 @@ LL | struct SA(i32); | ^^^^^^^^^ error[E0588]: packed type cannot transitively contain a `#[repr(align)]` type - --> $DIR/repr-packed-contains-align.rs:46:1 + --> $DIR/repr-packed-contains-align.rs:49:1 | LL | union UF { | ^^^^^^^^ @@ -124,12 +124,12 @@ note: `SA` has a `#[repr(align)]` attribute LL | struct SA(i32); | ^^^^^^^^^ note: `UF` contains a field of type `SB` - --> $DIR/repr-packed-contains-align.rs:47:5 + --> $DIR/repr-packed-contains-align.rs:50:5 | LL | n: SB | ^ note: ...which contains a field of type `SA` - --> $DIR/repr-packed-contains-align.rs:7:11 + --> $DIR/repr-packed-contains-align.rs:8:11 | LL | struct SB(SA); | ^^ diff --git a/src/test/ui/rfc-2093-infer-outlives/explicit-union.rs b/src/test/ui/rfc-2093-infer-outlives/explicit-union.rs index ea8a3c177e9d7..871208b5ba785 100644 --- a/src/test/ui/rfc-2093-infer-outlives/explicit-union.rs +++ b/src/test/ui/rfc-2093-infer-outlives/explicit-union.rs @@ -1,11 +1,11 @@ #![feature(rustc_attrs)] -#![feature(untagged_unions)] #[rustc_outlives] union Foo<'b, U: Copy> { //~ ERROR rustc_outlives bar: Bar<'b, U> } +#[derive(Clone, Copy)] union Bar<'a, T: Copy> where T: 'a { x: &'a (), y: T, diff --git a/src/test/ui/rfc-2093-infer-outlives/explicit-union.stderr b/src/test/ui/rfc-2093-infer-outlives/explicit-union.stderr index 2c6d06aa8c7f5..16b64bdc29dd3 100644 --- a/src/test/ui/rfc-2093-infer-outlives/explicit-union.stderr +++ b/src/test/ui/rfc-2093-infer-outlives/explicit-union.stderr @@ -1,5 +1,5 @@ error: rustc_outlives - --> $DIR/explicit-union.rs:5:1 + --> $DIR/explicit-union.rs:4:1 | LL | union Foo<'b, U: Copy> { | ^^^^^^^^^^^^^^^^^^^^^^ diff --git a/src/test/ui/rfc-2093-infer-outlives/nested-union.rs b/src/test/ui/rfc-2093-infer-outlives/nested-union.rs index 0da3cc2ba1b04..27ebd0b54db5d 100644 --- a/src/test/ui/rfc-2093-infer-outlives/nested-union.rs +++ b/src/test/ui/rfc-2093-infer-outlives/nested-union.rs @@ -1,5 +1,4 @@ #![feature(rustc_attrs)] -#![feature(untagged_unions)] #[rustc_outlives] union Foo<'a, T: Copy> { //~ ERROR rustc_outlives @@ -7,6 +6,7 @@ union Foo<'a, T: Copy> { //~ ERROR rustc_outlives } // Type U needs to outlive lifetime 'b +#[derive(Clone, Copy)] union Bar<'b, U: Copy> { field2: &'b U } diff --git a/src/test/ui/rfc-2093-infer-outlives/nested-union.stderr b/src/test/ui/rfc-2093-infer-outlives/nested-union.stderr index 0116a2a68ceb2..a785c63ce3d99 100644 --- a/src/test/ui/rfc-2093-infer-outlives/nested-union.stderr +++ b/src/test/ui/rfc-2093-infer-outlives/nested-union.stderr @@ -1,5 +1,5 @@ error: rustc_outlives - --> $DIR/nested-union.rs:5:1 + --> $DIR/nested-union.rs:4:1 | LL | union Foo<'a, T: Copy> { | ^^^^^^^^^^^^^^^^^^^^^^ diff --git a/src/test/ui/feature-gates/feature-gate-untagged_unions.rs b/src/test/ui/union/field_checks.rs similarity index 82% rename from src/test/ui/feature-gates/feature-gate-untagged_unions.rs rename to src/test/ui/union/field_checks.rs index a3c05efe6667e..216f7372a1cff 100644 --- a/src/test/ui/feature-gates/feature-gate-untagged_unions.rs +++ b/src/test/ui/union/field_checks.rs @@ -25,8 +25,8 @@ union U3 { a: String, //~ ERROR unions cannot contain fields that may need dropping } -union U32 { // field that does not drop but is not `Copy`, either -- this is the real feature gate test! - a: std::cell::RefCell, //~ ERROR unions with non-`Copy` fields other than `ManuallyDrop`, references, and tuples of such types are unstable +union U32 { // field that does not drop but is not `Copy`, either + a: std::cell::RefCell, //~ ERROR unions cannot contain fields that may need dropping } union U4 { diff --git a/src/test/ui/feature-gates/feature-gate-untagged_unions.stderr b/src/test/ui/union/field_checks.stderr similarity index 69% rename from src/test/ui/feature-gates/feature-gate-untagged_unions.stderr rename to src/test/ui/union/field_checks.stderr index 038b85a60fc7b..0e0e545b01a46 100644 --- a/src/test/ui/feature-gates/feature-gate-untagged_unions.stderr +++ b/src/test/ui/union/field_checks.stderr @@ -1,14 +1,5 @@ -error[E0658]: unions with non-`Copy` fields other than `ManuallyDrop`, references, and tuples of such types are unstable - --> $DIR/feature-gate-untagged_unions.rs:29:5 - | -LL | a: std::cell::RefCell, - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = note: see issue #55149 for more information - = help: add `#![feature(untagged_unions)]` to the crate attributes to enable - error[E0740]: unions cannot contain fields that may need dropping - --> $DIR/feature-gate-untagged_unions.rs:25:5 + --> $DIR/field_checks.rs:25:5 | LL | a: String, | ^^^^^^^^^ @@ -20,7 +11,19 @@ LL | a: std::mem::ManuallyDrop, | +++++++++++++++++++++++ + error[E0740]: unions cannot contain fields that may need dropping - --> $DIR/feature-gate-untagged_unions.rs:33:5 + --> $DIR/field_checks.rs:29:5 + | +LL | a: std::cell::RefCell, + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: a type is guaranteed not to need dropping when it implements `Copy`, or when it is the special `ManuallyDrop<_>` type +help: when the type does not implement `Copy`, wrap it inside a `ManuallyDrop<_>` and ensure it is manually dropped + | +LL | a: std::mem::ManuallyDrop>, + | +++++++++++++++++++++++ + + +error[E0740]: unions cannot contain fields that may need dropping + --> $DIR/field_checks.rs:33:5 | LL | a: T, | ^^^^ @@ -32,7 +35,7 @@ LL | a: std::mem::ManuallyDrop, | +++++++++++++++++++++++ + error[E0740]: unions cannot contain fields that may need dropping - --> $DIR/feature-gate-untagged_unions.rs:45:5 + --> $DIR/field_checks.rs:45:5 | LL | nest: U5, | ^^^^^^^^ @@ -45,5 +48,4 @@ LL | nest: std::mem::ManuallyDrop, error: aborting due to 4 previous errors -Some errors have detailed explanations: E0658, E0740. -For more information about an error, try `rustc --explain E0658`. +For more information about this error, try `rustc --explain E0740`. diff --git a/src/test/ui/union/issue-41073.rs b/src/test/ui/union/issue-41073.rs index 80474b807e7f3..4dfdc606bb409 100644 --- a/src/test/ui/union/issue-41073.rs +++ b/src/test/ui/union/issue-41073.rs @@ -1,5 +1,3 @@ -#![feature(untagged_unions)] - union Test { a: A, //~ ERROR unions cannot contain fields that may need dropping b: B diff --git a/src/test/ui/union/issue-41073.stderr b/src/test/ui/union/issue-41073.stderr index 7d4208b10da80..b3887fa0f90be 100644 --- a/src/test/ui/union/issue-41073.stderr +++ b/src/test/ui/union/issue-41073.stderr @@ -1,5 +1,5 @@ error[E0740]: unions cannot contain fields that may need dropping - --> $DIR/issue-41073.rs:4:5 + --> $DIR/issue-41073.rs:2:5 | LL | a: A, | ^^^^ diff --git a/src/test/ui/union/union-borrow-move-parent-sibling.mirunsafeck.stderr b/src/test/ui/union/union-borrow-move-parent-sibling.mirunsafeck.stderr index e785a2ee7335d..ca02de4c61bb8 100644 --- a/src/test/ui/union/union-borrow-move-parent-sibling.mirunsafeck.stderr +++ b/src/test/ui/union/union-borrow-move-parent-sibling.mirunsafeck.stderr @@ -1,49 +1,69 @@ -error[E0502]: cannot borrow `u` (via `u.y`) as immutable because it is also borrowed as mutable (via `u.x.0`) +error[E0502]: cannot borrow `u` (via `u.y`) as immutable because it is also borrowed as mutable (via `u.x`) --> $DIR/union-borrow-move-parent-sibling.rs:56:13 | -LL | let a = &mut u.x.0; - | ---------- mutable borrow occurs here (via `u.x.0`) +LL | let a = &mut (*u.x).0; + | --- mutable borrow occurs here (via `u.x`) LL | let b = &u.y; - | ^^^^ immutable borrow of `u.y` -- which overlaps with `u.x.0` -- occurs here + | ^^^^ immutable borrow of `u.y` -- which overlaps with `u.x` -- occurs here LL | use_borrow(a); | - mutable borrow later used here | - = note: `u.y` is a field of the union `U`, so it overlaps the field `u.x.0` + = note: `u.y` is a field of the union `U`, so it overlaps the field `u.x` + +error[E0507]: cannot move out of dereference of `ManuallyDrop<((MockVec, MockVec), MockVec)>` + --> $DIR/union-borrow-move-parent-sibling.rs:62:13 + | +LL | let a = u.x.0; + | ^^^^^ + | | + | move occurs because value has type `(MockVec, MockVec)`, which does not implement the `Copy` trait + | help: consider borrowing here: `&u.x.0` error[E0382]: use of moved value: `u` - --> $DIR/union-borrow-move-parent-sibling.rs:63:13 + --> $DIR/union-borrow-move-parent-sibling.rs:64:13 | -LL | let u = U { x: ((MockVec::new(), MockVec::new()), MockVec::new()) }; +LL | let u = U { x: ManuallyDrop::new(((MockVec::new(), MockVec::new()), MockVec::new())) }; | - move occurs because `u` has type `U`, which does not implement the `Copy` trait LL | let a = u.x.0; - | ----- value moved here +LL | let a = u.x; + | --- value moved here LL | let b = u.y; | ^^^ value used here after move -error[E0502]: cannot borrow `u` (via `u.y`) as immutable because it is also borrowed as mutable (via `u.x.0.0`) - --> $DIR/union-borrow-move-parent-sibling.rs:69:13 +error[E0502]: cannot borrow `u` (via `u.y`) as immutable because it is also borrowed as mutable (via `u.x`) + --> $DIR/union-borrow-move-parent-sibling.rs:70:13 | -LL | let a = &mut (u.x.0).0; - | -------------- mutable borrow occurs here (via `u.x.0.0`) +LL | let a = &mut ((*u.x).0).0; + | --- mutable borrow occurs here (via `u.x`) LL | let b = &u.y; - | ^^^^ immutable borrow of `u.y` -- which overlaps with `u.x.0.0` -- occurs here + | ^^^^ immutable borrow of `u.y` -- which overlaps with `u.x` -- occurs here LL | use_borrow(a); | - mutable borrow later used here | - = note: `u.y` is a field of the union `U`, so it overlaps the field `u.x.0.0` + = note: `u.y` is a field of the union `U`, so it overlaps the field `u.x` -error[E0382]: use of moved value: `u` +error[E0507]: cannot move out of dereference of `ManuallyDrop<((MockVec, MockVec), MockVec)>` --> $DIR/union-borrow-move-parent-sibling.rs:76:13 | -LL | let u = U { x: ((MockVec::new(), MockVec::new()), MockVec::new()) }; +LL | let a = (u.x.0).0; + | ^^^^^^^^^ + | | + | move occurs because value has type `MockVec`, which does not implement the `Copy` trait + | help: consider borrowing here: `&(u.x.0).0` + +error[E0382]: use of moved value: `u` + --> $DIR/union-borrow-move-parent-sibling.rs:78:13 + | +LL | let u = U { x: ManuallyDrop::new(((MockVec::new(), MockVec::new()), MockVec::new())) }; | - move occurs because `u` has type `U`, which does not implement the `Copy` trait LL | let a = (u.x.0).0; - | --------- value moved here +LL | let a = u.x; + | --- value moved here LL | let b = u.y; | ^^^ value used here after move error[E0502]: cannot borrow `u` (via `u.x`) as immutable because it is also borrowed as mutable (via `u.y`) - --> $DIR/union-borrow-move-parent-sibling.rs:82:13 + --> $DIR/union-borrow-move-parent-sibling.rs:84:13 | LL | let a = &mut *u.y; | --- mutable borrow occurs here (via `u.y`) @@ -54,7 +74,7 @@ LL | use_borrow(a); | = note: `u.x` is a field of the union `U`, so it overlaps the field `u.y` -error: aborting due to 5 previous errors +error: aborting due to 7 previous errors -Some errors have detailed explanations: E0382, E0502. +Some errors have detailed explanations: E0382, E0502, E0507. For more information about an error, try `rustc --explain E0382`. diff --git a/src/test/ui/union/union-borrow-move-parent-sibling.rs b/src/test/ui/union/union-borrow-move-parent-sibling.rs index e56d87255dbaf..83781c5e55092 100644 --- a/src/test/ui/union/union-borrow-move-parent-sibling.rs +++ b/src/test/ui/union/union-borrow-move-parent-sibling.rs @@ -1,10 +1,10 @@ // revisions: mirunsafeck thirunsafeck // [thirunsafeck]compile-flags: -Z thir-unsafeck -#![feature(untagged_unions)] #![allow(unused)] use std::ops::{Deref, DerefMut}; +use std::mem::ManuallyDrop; #[derive(Default)] struct MockBox { @@ -44,47 +44,49 @@ impl DerefMut for MockVec { union U { - x: ((MockVec, MockVec), MockVec), - y: MockBox>, + x: ManuallyDrop<((MockVec, MockVec), MockVec)>, + y: ManuallyDrop>>, } fn use_borrow(_: &T) {} unsafe fn parent_sibling_borrow() { - let mut u = U { x: ((MockVec::new(), MockVec::new()), MockVec::new()) }; - let a = &mut u.x.0; + let mut u = U { x: ManuallyDrop::new(((MockVec::new(), MockVec::new()), MockVec::new())) }; + let a = &mut (*u.x).0; let b = &u.y; //~ ERROR cannot borrow `u` (via `u.y`) use_borrow(a); } unsafe fn parent_sibling_move() { - let u = U { x: ((MockVec::new(), MockVec::new()), MockVec::new()) }; - let a = u.x.0; + let u = U { x: ManuallyDrop::new(((MockVec::new(), MockVec::new()), MockVec::new())) }; + let a = u.x.0; //~ERROR cannot move out of dereference + let a = u.x; let b = u.y; //~ ERROR use of moved value: `u` } unsafe fn grandparent_sibling_borrow() { - let mut u = U { x: ((MockVec::new(), MockVec::new()), MockVec::new()) }; - let a = &mut (u.x.0).0; + let mut u = U { x: ManuallyDrop::new(((MockVec::new(), MockVec::new()), MockVec::new())) }; + let a = &mut ((*u.x).0).0; let b = &u.y; //~ ERROR cannot borrow `u` (via `u.y`) use_borrow(a); } unsafe fn grandparent_sibling_move() { - let u = U { x: ((MockVec::new(), MockVec::new()), MockVec::new()) }; - let a = (u.x.0).0; + let u = U { x: ManuallyDrop::new(((MockVec::new(), MockVec::new()), MockVec::new())) }; + let a = (u.x.0).0; //~ERROR cannot move out of dereference + let a = u.x; let b = u.y; //~ ERROR use of moved value: `u` } unsafe fn deref_sibling_borrow() { - let mut u = U { y: MockBox::default() }; + let mut u = U { y: ManuallyDrop::new(MockBox::default()) }; let a = &mut *u.y; let b = &u.x; //~ ERROR cannot borrow `u` (via `u.x`) use_borrow(a); } unsafe fn deref_sibling_move() { - let u = U { x: ((MockVec::new(), MockVec::new()), MockVec::new()) }; + let u = U { x: ManuallyDrop::new(((MockVec::new(), MockVec::new()), MockVec::new())) }; // No way to test deref-move without Box in union // let a = *u.y; // let b = u.x; ERROR use of moved value: `u` diff --git a/src/test/ui/union/union-borrow-move-parent-sibling.thirunsafeck.stderr b/src/test/ui/union/union-borrow-move-parent-sibling.thirunsafeck.stderr index e785a2ee7335d..ca02de4c61bb8 100644 --- a/src/test/ui/union/union-borrow-move-parent-sibling.thirunsafeck.stderr +++ b/src/test/ui/union/union-borrow-move-parent-sibling.thirunsafeck.stderr @@ -1,49 +1,69 @@ -error[E0502]: cannot borrow `u` (via `u.y`) as immutable because it is also borrowed as mutable (via `u.x.0`) +error[E0502]: cannot borrow `u` (via `u.y`) as immutable because it is also borrowed as mutable (via `u.x`) --> $DIR/union-borrow-move-parent-sibling.rs:56:13 | -LL | let a = &mut u.x.0; - | ---------- mutable borrow occurs here (via `u.x.0`) +LL | let a = &mut (*u.x).0; + | --- mutable borrow occurs here (via `u.x`) LL | let b = &u.y; - | ^^^^ immutable borrow of `u.y` -- which overlaps with `u.x.0` -- occurs here + | ^^^^ immutable borrow of `u.y` -- which overlaps with `u.x` -- occurs here LL | use_borrow(a); | - mutable borrow later used here | - = note: `u.y` is a field of the union `U`, so it overlaps the field `u.x.0` + = note: `u.y` is a field of the union `U`, so it overlaps the field `u.x` + +error[E0507]: cannot move out of dereference of `ManuallyDrop<((MockVec, MockVec), MockVec)>` + --> $DIR/union-borrow-move-parent-sibling.rs:62:13 + | +LL | let a = u.x.0; + | ^^^^^ + | | + | move occurs because value has type `(MockVec, MockVec)`, which does not implement the `Copy` trait + | help: consider borrowing here: `&u.x.0` error[E0382]: use of moved value: `u` - --> $DIR/union-borrow-move-parent-sibling.rs:63:13 + --> $DIR/union-borrow-move-parent-sibling.rs:64:13 | -LL | let u = U { x: ((MockVec::new(), MockVec::new()), MockVec::new()) }; +LL | let u = U { x: ManuallyDrop::new(((MockVec::new(), MockVec::new()), MockVec::new())) }; | - move occurs because `u` has type `U`, which does not implement the `Copy` trait LL | let a = u.x.0; - | ----- value moved here +LL | let a = u.x; + | --- value moved here LL | let b = u.y; | ^^^ value used here after move -error[E0502]: cannot borrow `u` (via `u.y`) as immutable because it is also borrowed as mutable (via `u.x.0.0`) - --> $DIR/union-borrow-move-parent-sibling.rs:69:13 +error[E0502]: cannot borrow `u` (via `u.y`) as immutable because it is also borrowed as mutable (via `u.x`) + --> $DIR/union-borrow-move-parent-sibling.rs:70:13 | -LL | let a = &mut (u.x.0).0; - | -------------- mutable borrow occurs here (via `u.x.0.0`) +LL | let a = &mut ((*u.x).0).0; + | --- mutable borrow occurs here (via `u.x`) LL | let b = &u.y; - | ^^^^ immutable borrow of `u.y` -- which overlaps with `u.x.0.0` -- occurs here + | ^^^^ immutable borrow of `u.y` -- which overlaps with `u.x` -- occurs here LL | use_borrow(a); | - mutable borrow later used here | - = note: `u.y` is a field of the union `U`, so it overlaps the field `u.x.0.0` + = note: `u.y` is a field of the union `U`, so it overlaps the field `u.x` -error[E0382]: use of moved value: `u` +error[E0507]: cannot move out of dereference of `ManuallyDrop<((MockVec, MockVec), MockVec)>` --> $DIR/union-borrow-move-parent-sibling.rs:76:13 | -LL | let u = U { x: ((MockVec::new(), MockVec::new()), MockVec::new()) }; +LL | let a = (u.x.0).0; + | ^^^^^^^^^ + | | + | move occurs because value has type `MockVec`, which does not implement the `Copy` trait + | help: consider borrowing here: `&(u.x.0).0` + +error[E0382]: use of moved value: `u` + --> $DIR/union-borrow-move-parent-sibling.rs:78:13 + | +LL | let u = U { x: ManuallyDrop::new(((MockVec::new(), MockVec::new()), MockVec::new())) }; | - move occurs because `u` has type `U`, which does not implement the `Copy` trait LL | let a = (u.x.0).0; - | --------- value moved here +LL | let a = u.x; + | --- value moved here LL | let b = u.y; | ^^^ value used here after move error[E0502]: cannot borrow `u` (via `u.x`) as immutable because it is also borrowed as mutable (via `u.y`) - --> $DIR/union-borrow-move-parent-sibling.rs:82:13 + --> $DIR/union-borrow-move-parent-sibling.rs:84:13 | LL | let a = &mut *u.y; | --- mutable borrow occurs here (via `u.y`) @@ -54,7 +74,7 @@ LL | use_borrow(a); | = note: `u.x` is a field of the union `U`, so it overlaps the field `u.y` -error: aborting due to 5 previous errors +error: aborting due to 7 previous errors -Some errors have detailed explanations: E0382, E0502. +Some errors have detailed explanations: E0382, E0502, E0507. For more information about an error, try `rustc --explain E0382`. diff --git a/src/test/ui/union/union-custom-drop.rs b/src/test/ui/union/union-custom-drop.rs deleted file mode 100644 index 4b333631ec0f7..0000000000000 --- a/src/test/ui/union/union-custom-drop.rs +++ /dev/null @@ -1,19 +0,0 @@ -// test for a union with a field that's a union with a manual impl Drop -// Ensures we do not treat all unions as not having any drop glue. - -#![feature(untagged_unions)] - -union Foo { - bar: Bar, //~ ERROR unions cannot contain fields that may need dropping -} - -union Bar { - a: i32, - b: u32, -} - -impl Drop for Bar { - fn drop(&mut self) {} -} - -fn main() {} diff --git a/src/test/ui/union/union-custom-drop.stderr b/src/test/ui/union/union-custom-drop.stderr deleted file mode 100644 index b5579eeef0977..0000000000000 --- a/src/test/ui/union/union-custom-drop.stderr +++ /dev/null @@ -1,15 +0,0 @@ -error[E0740]: unions cannot contain fields that may need dropping - --> $DIR/union-custom-drop.rs:7:5 - | -LL | bar: Bar, - | ^^^^^^^^ - | - = note: a type is guaranteed not to need dropping when it implements `Copy`, or when it is the special `ManuallyDrop<_>` type -help: when the type does not implement `Copy`, wrap it inside a `ManuallyDrop<_>` and ensure it is manually dropped - | -LL | bar: std::mem::ManuallyDrop, - | +++++++++++++++++++++++ + - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0740`. diff --git a/src/test/ui/union/union-deref.mirunsafeck.stderr b/src/test/ui/union/union-deref.mirunsafeck.stderr index ff37e6fd9177a..be5e60ab88a59 100644 --- a/src/test/ui/union/union-deref.mirunsafeck.stderr +++ b/src/test/ui/union/union-deref.mirunsafeck.stderr @@ -1,5 +1,5 @@ error: not automatically applying `DerefMut` on `ManuallyDrop` union field - --> $DIR/union-deref.rs:17:14 + --> $DIR/union-deref.rs:16:14 | LL | unsafe { u.f.0 = Vec::new() }; | ^^^ @@ -8,7 +8,7 @@ LL | unsafe { u.f.0 = Vec::new() }; = help: add an explicit `*` if that is desired, or call `ptr::write` to not run the destructor error: not automatically applying `DerefMut` on `ManuallyDrop` union field - --> $DIR/union-deref.rs:19:19 + --> $DIR/union-deref.rs:18:19 | LL | unsafe { &mut u.f.0 }; | ^^^ @@ -17,7 +17,7 @@ LL | unsafe { &mut u.f.0 }; = help: add an explicit `*` if that is desired, or call `ptr::write` to not run the destructor error: not automatically applying `DerefMut` on `ManuallyDrop` union field - --> $DIR/union-deref.rs:21:14 + --> $DIR/union-deref.rs:20:14 | LL | unsafe { u.f.0.push(0) }; | ^^^ @@ -26,7 +26,7 @@ LL | unsafe { u.f.0.push(0) }; = help: add an explicit `*` if that is desired, or call `ptr::write` to not run the destructor error: not automatically applying `DerefMut` on `ManuallyDrop` union field - --> $DIR/union-deref.rs:25:14 + --> $DIR/union-deref.rs:24:14 | LL | unsafe { u.f.0.0 = Vec::new() }; | ^^^^^ @@ -35,7 +35,7 @@ LL | unsafe { u.f.0.0 = Vec::new() }; = help: add an explicit `*` if that is desired, or call `ptr::write` to not run the destructor error: not automatically applying `DerefMut` on `ManuallyDrop` union field - --> $DIR/union-deref.rs:27:19 + --> $DIR/union-deref.rs:26:19 | LL | unsafe { &mut u.f.0.0 }; | ^^^^^ @@ -44,7 +44,7 @@ LL | unsafe { &mut u.f.0.0 }; = help: add an explicit `*` if that is desired, or call `ptr::write` to not run the destructor error: not automatically applying `DerefMut` on `ManuallyDrop` union field - --> $DIR/union-deref.rs:29:14 + --> $DIR/union-deref.rs:28:14 | LL | unsafe { u.f.0.0.push(0) }; | ^^^^^ diff --git a/src/test/ui/union/union-deref.rs b/src/test/ui/union/union-deref.rs index 4bf2ba2f1bfce..5aa28d93f96ed 100644 --- a/src/test/ui/union/union-deref.rs +++ b/src/test/ui/union/union-deref.rs @@ -3,7 +3,6 @@ //! Test the part of RFC 2514 that is about not applying `DerefMut` coercions //! of union fields. -#![feature(untagged_unions)] use std::mem::ManuallyDrop; diff --git a/src/test/ui/union/union-deref.thirunsafeck.stderr b/src/test/ui/union/union-deref.thirunsafeck.stderr index ff37e6fd9177a..be5e60ab88a59 100644 --- a/src/test/ui/union/union-deref.thirunsafeck.stderr +++ b/src/test/ui/union/union-deref.thirunsafeck.stderr @@ -1,5 +1,5 @@ error: not automatically applying `DerefMut` on `ManuallyDrop` union field - --> $DIR/union-deref.rs:17:14 + --> $DIR/union-deref.rs:16:14 | LL | unsafe { u.f.0 = Vec::new() }; | ^^^ @@ -8,7 +8,7 @@ LL | unsafe { u.f.0 = Vec::new() }; = help: add an explicit `*` if that is desired, or call `ptr::write` to not run the destructor error: not automatically applying `DerefMut` on `ManuallyDrop` union field - --> $DIR/union-deref.rs:19:19 + --> $DIR/union-deref.rs:18:19 | LL | unsafe { &mut u.f.0 }; | ^^^ @@ -17,7 +17,7 @@ LL | unsafe { &mut u.f.0 }; = help: add an explicit `*` if that is desired, or call `ptr::write` to not run the destructor error: not automatically applying `DerefMut` on `ManuallyDrop` union field - --> $DIR/union-deref.rs:21:14 + --> $DIR/union-deref.rs:20:14 | LL | unsafe { u.f.0.push(0) }; | ^^^ @@ -26,7 +26,7 @@ LL | unsafe { u.f.0.push(0) }; = help: add an explicit `*` if that is desired, or call `ptr::write` to not run the destructor error: not automatically applying `DerefMut` on `ManuallyDrop` union field - --> $DIR/union-deref.rs:25:14 + --> $DIR/union-deref.rs:24:14 | LL | unsafe { u.f.0.0 = Vec::new() }; | ^^^^^ @@ -35,7 +35,7 @@ LL | unsafe { u.f.0.0 = Vec::new() }; = help: add an explicit `*` if that is desired, or call `ptr::write` to not run the destructor error: not automatically applying `DerefMut` on `ManuallyDrop` union field - --> $DIR/union-deref.rs:27:19 + --> $DIR/union-deref.rs:26:19 | LL | unsafe { &mut u.f.0.0 }; | ^^^^^ @@ -44,7 +44,7 @@ LL | unsafe { &mut u.f.0.0 }; = help: add an explicit `*` if that is desired, or call `ptr::write` to not run the destructor error: not automatically applying `DerefMut` on `ManuallyDrop` union field - --> $DIR/union-deref.rs:29:14 + --> $DIR/union-deref.rs:28:14 | LL | unsafe { u.f.0.0.push(0) }; | ^^^^^ diff --git a/src/test/ui/union/union-move.mirunsafeck.stderr b/src/test/ui/union/union-move.mirunsafeck.stderr index f55fbea6336e3..53050cf539eaf 100644 --- a/src/test/ui/union/union-move.mirunsafeck.stderr +++ b/src/test/ui/union/union-move.mirunsafeck.stderr @@ -27,7 +27,7 @@ LL | move_out(x.f1_nocopy); | ^^^^^^^^^^^ | | | cannot move out of here - | move occurs because `x.f1_nocopy` has type `RefCell`, which does not implement the `Copy` trait + | move occurs because `x.f1_nocopy` has type `ManuallyDrop>`, which does not implement the `Copy` trait error: aborting due to 3 previous errors diff --git a/src/test/ui/union/union-move.rs b/src/test/ui/union/union-move.rs index 8f78c30d67a55..b8b1ac8046a03 100644 --- a/src/test/ui/union/union-move.rs +++ b/src/test/ui/union/union-move.rs @@ -3,20 +3,20 @@ //! Test the behavior of moving out of non-`Copy` union fields. //! Avoid types that `Drop`, we want to focus on moving. -#![feature(untagged_unions)] use std::cell::RefCell; +use std::mem::ManuallyDrop; fn move_out(x: T) {} union U1 { - f1_nocopy: RefCell, - f2_nocopy: RefCell, + f1_nocopy: ManuallyDrop>, + f2_nocopy: ManuallyDrop>, f3_copy: i32, } union U2 { - f1_nocopy: RefCell, + f1_nocopy: ManuallyDrop>, } impl Drop for U2 { fn drop(&mut self) {} diff --git a/src/test/ui/union/union-move.thirunsafeck.stderr b/src/test/ui/union/union-move.thirunsafeck.stderr index f55fbea6336e3..53050cf539eaf 100644 --- a/src/test/ui/union/union-move.thirunsafeck.stderr +++ b/src/test/ui/union/union-move.thirunsafeck.stderr @@ -27,7 +27,7 @@ LL | move_out(x.f1_nocopy); | ^^^^^^^^^^^ | | | cannot move out of here - | move occurs because `x.f1_nocopy` has type `RefCell`, which does not implement the `Copy` trait + | move occurs because `x.f1_nocopy` has type `ManuallyDrop>`, which does not implement the `Copy` trait error: aborting due to 3 previous errors diff --git a/src/test/ui/union/union-nonrepresentable.rs b/src/test/ui/union/union-nonrepresentable.rs index 4dbd97ea957ba..afa73857ac2a5 100644 --- a/src/test/ui/union/union-nonrepresentable.rs +++ b/src/test/ui/union/union-nonrepresentable.rs @@ -1,8 +1,7 @@ -#![feature(untagged_unions)] union U { //~ ERROR recursive type `U` has infinite size a: u8, - b: U, + b: std::mem::ManuallyDrop, } fn main() {} diff --git a/src/test/ui/union/union-nonrepresentable.stderr b/src/test/ui/union/union-nonrepresentable.stderr index 7da7c870e704b..a2380d8bc0e99 100644 --- a/src/test/ui/union/union-nonrepresentable.stderr +++ b/src/test/ui/union/union-nonrepresentable.stderr @@ -1,16 +1,16 @@ error[E0072]: recursive type `U` has infinite size - --> $DIR/union-nonrepresentable.rs:3:1 + --> $DIR/union-nonrepresentable.rs:2:1 | LL | union U { | ^^^^^^^ recursive type has infinite size LL | a: u8, -LL | b: U, - | - recursive without indirection +LL | b: std::mem::ManuallyDrop, + | ------------------------- recursive without indirection | help: insert some indirection (e.g., a `Box`, `Rc`, or `&`) to make `U` representable | -LL | b: Box, - | ++++ + +LL | b: Box>, + | ++++ + error: aborting due to previous error diff --git a/src/test/ui/union/union-sized-field.rs b/src/test/ui/union/union-sized-field.rs index b84cb3eff56f6..cb852eff0c60a 100644 --- a/src/test/ui/union/union-sized-field.rs +++ b/src/test/ui/union/union-sized-field.rs @@ -1,18 +1,18 @@ -#![feature(untagged_unions)] +use std::mem::ManuallyDrop; union Foo { - value: T, + value: ManuallyDrop, //~^ ERROR the size for values of type } struct Foo2 { - value: T, + value: ManuallyDrop, //~^ ERROR the size for values of type t: u32, } enum Foo3 { - Value(T), + Value(ManuallyDrop), //~^ ERROR the size for values of type } diff --git a/src/test/ui/union/union-sized-field.stderr b/src/test/ui/union/union-sized-field.stderr index 3fe6e71f3b863..771e8f2619995 100644 --- a/src/test/ui/union/union-sized-field.stderr +++ b/src/test/ui/union/union-sized-field.stderr @@ -3,9 +3,10 @@ error[E0277]: the size for values of type `T` cannot be known at compilation tim | LL | union Foo { | - this type parameter needs to be `std::marker::Sized` -LL | value: T, - | ^ doesn't have a size known at compile-time +LL | value: ManuallyDrop, + | ^^^^^^^^^^^^^^^ doesn't have a size known at compile-time | + = note: required because it appears within the type `ManuallyDrop` = note: no field of a union may have a dynamically sized type = help: change the field's type to have a statically known size help: consider removing the `?Sized` bound to make the type parameter `Sized` @@ -15,21 +16,22 @@ LL + union Foo { | help: borrowed types always have a statically known size | -LL | value: &T, +LL | value: &ManuallyDrop, | + help: the `Box` type always has a statically known size and allocates its contents in the heap | -LL | value: Box, - | ++++ + +LL | value: Box>, + | ++++ + error[E0277]: the size for values of type `T` cannot be known at compilation time --> $DIR/union-sized-field.rs:9:12 | LL | struct Foo2 { | - this type parameter needs to be `std::marker::Sized` -LL | value: T, - | ^ doesn't have a size known at compile-time +LL | value: ManuallyDrop, + | ^^^^^^^^^^^^^^^ doesn't have a size known at compile-time | + = note: required because it appears within the type `ManuallyDrop` = note: only the last field of a struct may have a dynamically sized type = help: change the field's type to have a statically known size help: consider removing the `?Sized` bound to make the type parameter `Sized` @@ -39,21 +41,22 @@ LL + struct Foo2 { | help: borrowed types always have a statically known size | -LL | value: &T, +LL | value: &ManuallyDrop, | + help: the `Box` type always has a statically known size and allocates its contents in the heap | -LL | value: Box, - | ++++ + +LL | value: Box>, + | ++++ + error[E0277]: the size for values of type `T` cannot be known at compilation time --> $DIR/union-sized-field.rs:15:11 | LL | enum Foo3 { | - this type parameter needs to be `std::marker::Sized` -LL | Value(T), - | ^ doesn't have a size known at compile-time +LL | Value(ManuallyDrop), + | ^^^^^^^^^^^^^^^ doesn't have a size known at compile-time | + = note: required because it appears within the type `ManuallyDrop` = note: no field of an enum variant may have a dynamically sized type = help: change the field's type to have a statically known size help: consider removing the `?Sized` bound to make the type parameter `Sized` @@ -63,12 +66,12 @@ LL + enum Foo3 { | help: borrowed types always have a statically known size | -LL | Value(&T), +LL | Value(&ManuallyDrop), | + help: the `Box` type always has a statically known size and allocates its contents in the heap | -LL | Value(Box), - | ++++ + +LL | Value(Box>), + | ++++ + error: aborting due to 3 previous errors diff --git a/src/test/ui/union/union-unsafe.mir.stderr b/src/test/ui/union/union-unsafe.mir.stderr index 318b00ddea94e..0aefa21c94480 100644 --- a/src/test/ui/union/union-unsafe.mir.stderr +++ b/src/test/ui/union/union-unsafe.mir.stderr @@ -1,5 +1,5 @@ error[E0133]: access to union field is unsafe and requires unsafe function or block - --> $DIR/union-unsafe.rs:34:5 + --> $DIR/union-unsafe.rs:33:5 | LL | *(u.p) = 13; | ^^^^^^^^^^^ access to union field @@ -7,23 +7,15 @@ LL | *(u.p) = 13; = note: the field may not be properly initialized: using uninitialized data will cause undefined behavior error[E0133]: assignment to union field that might need dropping is unsafe and requires unsafe function or block - --> $DIR/union-unsafe.rs:39:5 + --> $DIR/union-unsafe.rs:38:5 | -LL | u.a = (RefCell::new(0), 1); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ assignment to union field that might need dropping - | - = note: the previous content of the field will be dropped, which causes undefined behavior if the field was not properly initialized - -error[E0133]: assignment to union field that might need dropping is unsafe and requires unsafe function or block - --> $DIR/union-unsafe.rs:40:5 - | -LL | u.a.0 = RefCell::new(0); - | ^^^^^^^^^^^^^^^^^^^^^^^ assignment to union field that might need dropping +LL | u.a = (ManuallyDrop::new(RefCell::new(0)), 1); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ assignment to union field that might need dropping | = note: the previous content of the field will be dropped, which causes undefined behavior if the field was not properly initialized error[E0133]: access to union field is unsafe and requires unsafe function or block - --> $DIR/union-unsafe.rs:47:6 + --> $DIR/union-unsafe.rs:46:6 | LL | *u3.a = T::default(); | ^^^^ access to union field @@ -31,7 +23,7 @@ LL | *u3.a = T::default(); = note: the field may not be properly initialized: using uninitialized data will cause undefined behavior error[E0133]: access to union field is unsafe and requires unsafe function or block - --> $DIR/union-unsafe.rs:53:6 + --> $DIR/union-unsafe.rs:52:6 | LL | *u3.a = T::default(); | ^^^^ access to union field @@ -39,7 +31,7 @@ LL | *u3.a = T::default(); = note: the field may not be properly initialized: using uninitialized data will cause undefined behavior error[E0133]: access to union field is unsafe and requires unsafe function or block - --> $DIR/union-unsafe.rs:61:13 + --> $DIR/union-unsafe.rs:60:13 | LL | let a = u1.a; | ^^^^ access to union field @@ -47,7 +39,7 @@ LL | let a = u1.a; = note: the field may not be properly initialized: using uninitialized data will cause undefined behavior error[E0133]: access to union field is unsafe and requires unsafe function or block - --> $DIR/union-unsafe.rs:64:14 + --> $DIR/union-unsafe.rs:63:14 | LL | let U1 { a } = u1; | ^ access to union field @@ -55,7 +47,7 @@ LL | let U1 { a } = u1; = note: the field may not be properly initialized: using uninitialized data will cause undefined behavior error[E0133]: access to union field is unsafe and requires unsafe function or block - --> $DIR/union-unsafe.rs:65:12 + --> $DIR/union-unsafe.rs:64:12 | LL | if let U1 { a: 12 } = u1 {} | ^^^^^^^^^^^^ access to union field @@ -63,7 +55,7 @@ LL | if let U1 { a: 12 } = u1 {} = note: the field may not be properly initialized: using uninitialized data will cause undefined behavior error[E0133]: access to union field is unsafe and requires unsafe function or block - --> $DIR/union-unsafe.rs:70:6 + --> $DIR/union-unsafe.rs:69:6 | LL | *u2.a = String::from("new"); | ^^^^ access to union field @@ -71,7 +63,7 @@ LL | *u2.a = String::from("new"); = note: the field may not be properly initialized: using uninitialized data will cause undefined behavior error[E0133]: access to union field is unsafe and requires unsafe function or block - --> $DIR/union-unsafe.rs:74:6 + --> $DIR/union-unsafe.rs:73:6 | LL | *u3.a = 1; | ^^^^ access to union field @@ -79,13 +71,13 @@ LL | *u3.a = 1; = note: the field may not be properly initialized: using uninitialized data will cause undefined behavior error[E0133]: access to union field is unsafe and requires unsafe function or block - --> $DIR/union-unsafe.rs:78:6 + --> $DIR/union-unsafe.rs:77:6 | LL | *u3.a = String::from("new"); | ^^^^ access to union field | = note: the field may not be properly initialized: using uninitialized data will cause undefined behavior -error: aborting due to 11 previous errors +error: aborting due to 10 previous errors For more information about this error, try `rustc --explain E0133`. diff --git a/src/test/ui/union/union-unsafe.rs b/src/test/ui/union/union-unsafe.rs index 3cb3a18cb7544..7e9d9052a6723 100644 --- a/src/test/ui/union/union-unsafe.rs +++ b/src/test/ui/union/union-unsafe.rs @@ -1,7 +1,6 @@ // revisions: mir thir // [thir]compile-flags: -Z thir-unsafeck -#![feature(untagged_unions)] use std::mem::ManuallyDrop; use std::cell::RefCell; @@ -26,7 +25,7 @@ union URef { } union URefCell { // field that does not drop but is not `Copy`, either - a: (RefCell, i32), + a: (ManuallyDrop>, i32), } fn deref_union_field(mut u: URef) { @@ -36,8 +35,8 @@ fn deref_union_field(mut u: URef) { fn assign_noncopy_union_field(mut u: URefCell) { // FIXME(thir-unsafeck) - u.a = (RefCell::new(0), 1); //~ ERROR assignment to union field that might need dropping - u.a.0 = RefCell::new(0); //~ ERROR assignment to union field that might need dropping + u.a = (ManuallyDrop::new(RefCell::new(0)), 1); //~ ERROR assignment to union field + u.a.0 = ManuallyDrop::new(RefCell::new(0)); // OK (assignment does not drop) u.a.1 = 1; // OK } diff --git a/src/test/ui/union/union-unsafe.thir.stderr b/src/test/ui/union/union-unsafe.thir.stderr index a8c3886657f43..dbfd92f05d951 100644 --- a/src/test/ui/union/union-unsafe.thir.stderr +++ b/src/test/ui/union/union-unsafe.thir.stderr @@ -1,5 +1,5 @@ error[E0133]: access to union field is unsafe and requires unsafe function or block - --> $DIR/union-unsafe.rs:34:6 + --> $DIR/union-unsafe.rs:33:6 | LL | *(u.p) = 13; | ^^^^^ access to union field @@ -7,23 +7,15 @@ LL | *(u.p) = 13; = note: the field may not be properly initialized: using uninitialized data will cause undefined behavior error[E0133]: assignment to union field that might need dropping is unsafe and requires unsafe function or block - --> $DIR/union-unsafe.rs:39:5 + --> $DIR/union-unsafe.rs:38:5 | -LL | u.a = (RefCell::new(0), 1); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ assignment to union field that might need dropping - | - = note: the previous content of the field will be dropped, which causes undefined behavior if the field was not properly initialized - -error[E0133]: assignment to union field that might need dropping is unsafe and requires unsafe function or block - --> $DIR/union-unsafe.rs:40:5 - | -LL | u.a.0 = RefCell::new(0); - | ^^^^^^^^^^^^^^^^^^^^^^^ assignment to union field that might need dropping +LL | u.a = (ManuallyDrop::new(RefCell::new(0)), 1); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ assignment to union field that might need dropping | = note: the previous content of the field will be dropped, which causes undefined behavior if the field was not properly initialized error[E0133]: access to union field is unsafe and requires unsafe function or block - --> $DIR/union-unsafe.rs:47:6 + --> $DIR/union-unsafe.rs:46:6 | LL | *u3.a = T::default(); | ^^^^ access to union field @@ -31,7 +23,7 @@ LL | *u3.a = T::default(); = note: the field may not be properly initialized: using uninitialized data will cause undefined behavior error[E0133]: access to union field is unsafe and requires unsafe function or block - --> $DIR/union-unsafe.rs:53:6 + --> $DIR/union-unsafe.rs:52:6 | LL | *u3.a = T::default(); | ^^^^ access to union field @@ -39,7 +31,7 @@ LL | *u3.a = T::default(); = note: the field may not be properly initialized: using uninitialized data will cause undefined behavior error[E0133]: access to union field is unsafe and requires unsafe function or block - --> $DIR/union-unsafe.rs:61:13 + --> $DIR/union-unsafe.rs:60:13 | LL | let a = u1.a; | ^^^^ access to union field @@ -47,7 +39,7 @@ LL | let a = u1.a; = note: the field may not be properly initialized: using uninitialized data will cause undefined behavior error[E0133]: access to union field is unsafe and requires unsafe function or block - --> $DIR/union-unsafe.rs:64:14 + --> $DIR/union-unsafe.rs:63:14 | LL | let U1 { a } = u1; | ^ access to union field @@ -55,7 +47,7 @@ LL | let U1 { a } = u1; = note: the field may not be properly initialized: using uninitialized data will cause undefined behavior error[E0133]: access to union field is unsafe and requires unsafe function or block - --> $DIR/union-unsafe.rs:65:8 + --> $DIR/union-unsafe.rs:64:8 | LL | if let U1 { a: 12 } = u1 {} | ^^^^^^^^^^^^^^^^^^^^^ access to union field @@ -63,7 +55,7 @@ LL | if let U1 { a: 12 } = u1 {} = note: the field may not be properly initialized: using uninitialized data will cause undefined behavior error[E0133]: access to union field is unsafe and requires unsafe function or block - --> $DIR/union-unsafe.rs:70:6 + --> $DIR/union-unsafe.rs:69:6 | LL | *u2.a = String::from("new"); | ^^^^ access to union field @@ -71,7 +63,7 @@ LL | *u2.a = String::from("new"); = note: the field may not be properly initialized: using uninitialized data will cause undefined behavior error[E0133]: access to union field is unsafe and requires unsafe function or block - --> $DIR/union-unsafe.rs:74:6 + --> $DIR/union-unsafe.rs:73:6 | LL | *u3.a = 1; | ^^^^ access to union field @@ -79,13 +71,13 @@ LL | *u3.a = 1; = note: the field may not be properly initialized: using uninitialized data will cause undefined behavior error[E0133]: access to union field is unsafe and requires unsafe function or block - --> $DIR/union-unsafe.rs:78:6 + --> $DIR/union-unsafe.rs:77:6 | LL | *u3.a = String::from("new"); | ^^^^ access to union field | = note: the field may not be properly initialized: using uninitialized data will cause undefined behavior -error: aborting due to 11 previous errors +error: aborting due to 10 previous errors For more information about this error, try `rustc --explain E0133`. diff --git a/src/test/ui/union/union-unsized.mirunsafeck.stderr b/src/test/ui/union/union-unsized.mirunsafeck.stderr index 36e782ac0424d..59ab835fba22d 100644 --- a/src/test/ui/union/union-unsized.mirunsafeck.stderr +++ b/src/test/ui/union/union-unsized.mirunsafeck.stderr @@ -1,5 +1,5 @@ error[E0277]: the size for values of type `str` cannot be known at compilation time - --> $DIR/union-unsized.rs:7:8 + --> $DIR/union-unsized.rs:5:8 | LL | a: str, | ^^^ doesn't have a size known at compile-time @@ -17,7 +17,7 @@ LL | a: Box, | ++++ + error[E0277]: the size for values of type `str` cannot be known at compilation time - --> $DIR/union-unsized.rs:15:8 + --> $DIR/union-unsized.rs:13:8 | LL | b: str, | ^^^ doesn't have a size known at compile-time diff --git a/src/test/ui/union/union-unsized.rs b/src/test/ui/union/union-unsized.rs index e9792f527dc71..8e897d7d3c6d6 100644 --- a/src/test/ui/union/union-unsized.rs +++ b/src/test/ui/union/union-unsized.rs @@ -1,8 +1,6 @@ // revisions: mirunsafeck thirunsafeck // [thirunsafeck]compile-flags: -Z thir-unsafeck -#![feature(untagged_unions)] - union U { a: str, //~^ ERROR the size for values of type diff --git a/src/test/ui/union/union-unsized.thirunsafeck.stderr b/src/test/ui/union/union-unsized.thirunsafeck.stderr index 36e782ac0424d..59ab835fba22d 100644 --- a/src/test/ui/union/union-unsized.thirunsafeck.stderr +++ b/src/test/ui/union/union-unsized.thirunsafeck.stderr @@ -1,5 +1,5 @@ error[E0277]: the size for values of type `str` cannot be known at compilation time - --> $DIR/union-unsized.rs:7:8 + --> $DIR/union-unsized.rs:5:8 | LL | a: str, | ^^^ doesn't have a size known at compile-time @@ -17,7 +17,7 @@ LL | a: Box, | ++++ + error[E0277]: the size for values of type `str` cannot be known at compilation time - --> $DIR/union-unsized.rs:15:8 + --> $DIR/union-unsized.rs:13:8 | LL | b: str, | ^^^ doesn't have a size known at compile-time diff --git a/src/test/ui/unsafe/union-assignop.mirunsafeck.stderr b/src/test/ui/unsafe/union-assignop.mirunsafeck.stderr index cd338ac9e3a27..0ecd5203dd9d9 100644 --- a/src/test/ui/unsafe/union-assignop.mirunsafeck.stderr +++ b/src/test/ui/unsafe/union-assignop.mirunsafeck.stderr @@ -1,5 +1,5 @@ error[E0133]: access to union field is unsafe and requires unsafe function or block - --> $DIR/union-assignop.rs:20:5 + --> $DIR/union-assignop.rs:19:5 | LL | foo.a += 5; | ^^^^^^^^^^ access to union field @@ -7,20 +7,20 @@ LL | foo.a += 5; = note: the field may not be properly initialized: using uninitialized data will cause undefined behavior error[E0133]: access to union field is unsafe and requires unsafe function or block - --> $DIR/union-assignop.rs:21:5 + --> $DIR/union-assignop.rs:20:6 | -LL | foo.b += Dropping; - | ^^^^^ access to union field +LL | *foo.b += NonCopy; + | ^^^^^ access to union field | = note: the field may not be properly initialized: using uninitialized data will cause undefined behavior -error[E0133]: assignment to union field that might need dropping is unsafe and requires unsafe function or block - --> $DIR/union-assignop.rs:22:5 +error[E0133]: access to union field is unsafe and requires unsafe function or block + --> $DIR/union-assignop.rs:21:6 | -LL | foo.b = Dropping; - | ^^^^^^^^^^^^^^^^ assignment to union field that might need dropping +LL | *foo.b = NonCopy; + | ^^^^^ access to union field | - = note: the previous content of the field will be dropped, which causes undefined behavior if the field was not properly initialized + = note: the field may not be properly initialized: using uninitialized data will cause undefined behavior error[E0133]: access to union field is unsafe and requires unsafe function or block --> $DIR/union-assignop.rs:23:5 @@ -46,14 +46,6 @@ LL | foo.b = foo.b; | = note: the field may not be properly initialized: using uninitialized data will cause undefined behavior -error[E0133]: assignment to union field that might need dropping is unsafe and requires unsafe function or block - --> $DIR/union-assignop.rs:27:5 - | -LL | foo.b = foo.b; - | ^^^^^^^^^^^^^ assignment to union field that might need dropping - | - = note: the previous content of the field will be dropped, which causes undefined behavior if the field was not properly initialized - -error: aborting due to 7 previous errors +error: aborting due to 6 previous errors For more information about this error, try `rustc --explain E0133`. diff --git a/src/test/ui/unsafe/union-assignop.rs b/src/test/ui/unsafe/union-assignop.rs index c4be20aa567b7..5e667cd10d59f 100644 --- a/src/test/ui/unsafe/union-assignop.rs +++ b/src/test/ui/unsafe/union-assignop.rs @@ -1,30 +1,29 @@ // revisions: mirunsafeck thirunsafeck // [thirunsafeck]compile-flags: -Z thir-unsafeck -#![feature(untagged_unions)] - use std::ops::AddAssign; +use std::mem::ManuallyDrop; -struct Dropping; -impl AddAssign for Dropping { +struct NonCopy; +impl AddAssign for NonCopy { fn add_assign(&mut self, _: Self) {} } union Foo { a: u8, // non-dropping - b: Dropping, // treated as dropping + b: ManuallyDrop, } fn main() { let mut foo = Foo { a: 42 }; foo.a += 5; //~ ERROR access to union field is unsafe - foo.b += Dropping; //~ ERROR access to union field is unsafe - foo.b = Dropping; //~ ERROR assignment to union field that might need dropping is unsafe + *foo.b += NonCopy; //~ ERROR access to union field is unsafe + *foo.b = NonCopy; //~ ERROR access to union field is unsafe + foo.b = ManuallyDrop::new(NonCopy); foo.a; //~ ERROR access to union field is unsafe let foo = Foo { a: 42 }; foo.b; //~ ERROR access to union field is unsafe let mut foo = Foo { a: 42 }; foo.b = foo.b; //~^ ERROR access to union field is unsafe - //~| ERROR assignment to union field that might need dropping } diff --git a/src/test/ui/unsafe/union-assignop.thirunsafeck.stderr b/src/test/ui/unsafe/union-assignop.thirunsafeck.stderr index 71de421a2553e..24b357e762bba 100644 --- a/src/test/ui/unsafe/union-assignop.thirunsafeck.stderr +++ b/src/test/ui/unsafe/union-assignop.thirunsafeck.stderr @@ -1,5 +1,5 @@ error[E0133]: access to union field is unsafe and requires unsafe function or block - --> $DIR/union-assignop.rs:20:5 + --> $DIR/union-assignop.rs:19:5 | LL | foo.a += 5; | ^^^^^ access to union field @@ -7,20 +7,20 @@ LL | foo.a += 5; = note: the field may not be properly initialized: using uninitialized data will cause undefined behavior error[E0133]: access to union field is unsafe and requires unsafe function or block - --> $DIR/union-assignop.rs:21:5 + --> $DIR/union-assignop.rs:20:6 | -LL | foo.b += Dropping; - | ^^^^^ access to union field +LL | *foo.b += NonCopy; + | ^^^^^ access to union field | = note: the field may not be properly initialized: using uninitialized data will cause undefined behavior -error[E0133]: assignment to union field that might need dropping is unsafe and requires unsafe function or block - --> $DIR/union-assignop.rs:22:5 +error[E0133]: access to union field is unsafe and requires unsafe function or block + --> $DIR/union-assignop.rs:21:6 | -LL | foo.b = Dropping; - | ^^^^^^^^^^^^^^^^ assignment to union field that might need dropping +LL | *foo.b = NonCopy; + | ^^^^^ access to union field | - = note: the previous content of the field will be dropped, which causes undefined behavior if the field was not properly initialized + = note: the field may not be properly initialized: using uninitialized data will cause undefined behavior error[E0133]: access to union field is unsafe and requires unsafe function or block --> $DIR/union-assignop.rs:23:5 @@ -38,14 +38,6 @@ LL | foo.b; | = note: the field may not be properly initialized: using uninitialized data will cause undefined behavior -error[E0133]: assignment to union field that might need dropping is unsafe and requires unsafe function or block - --> $DIR/union-assignop.rs:27:5 - | -LL | foo.b = foo.b; - | ^^^^^^^^^^^^^ assignment to union field that might need dropping - | - = note: the previous content of the field will be dropped, which causes undefined behavior if the field was not properly initialized - error[E0133]: access to union field is unsafe and requires unsafe function or block --> $DIR/union-assignop.rs:27:13 | @@ -54,6 +46,6 @@ LL | foo.b = foo.b; | = note: the field may not be properly initialized: using uninitialized data will cause undefined behavior -error: aborting due to 7 previous errors +error: aborting due to 6 previous errors For more information about this error, try `rustc --explain E0133`. diff --git a/src/test/ui/unsafe/union-modification.rs b/src/test/ui/unsafe/union-modification.rs index 5c70b78df7c12..9a53ef9085200 100644 --- a/src/test/ui/unsafe/union-modification.rs +++ b/src/test/ui/unsafe/union-modification.rs @@ -2,8 +2,6 @@ // revisions: mir thir // [thir]compile-flags: -Z thir-unsafeck -#![feature(untagged_unions)] - union Foo { bar: i8, _blah: isize, diff --git a/src/test/ui/unsafe/union.rs b/src/test/ui/unsafe/union.rs index 5fe09933cfc48..4338d78eabb9d 100644 --- a/src/test/ui/unsafe/union.rs +++ b/src/test/ui/unsafe/union.rs @@ -1,19 +1,19 @@ // revisions: mir thir // [thir]compile-flags: -Z thir-unsafeck -#![feature(untagged_unions)] - union Foo { bar: i8, zst: (), pizza: Pizza, } +#[derive(Clone, Copy)] struct Pizza { topping: Option } #[allow(dead_code)] +#[derive(Clone, Copy)] enum PizzaTopping { Cheese, Pineapple, From 1cf6f5c01d835522597fff0273bd503605ad82ec Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 30 Jun 2022 08:40:06 -0400 Subject: [PATCH 18/29] assigning to a union field can never drop now --- compiler/rustc_middle/src/mir/query.rs | 6 ----- .../rustc_mir_build/src/check_unsafety.rs | 20 +++------------- .../rustc_mir_transform/src/check_unsafety.rs | 23 +++++++------------ src/test/ui/union/union-unsafe.mir.stderr | 10 +------- src/test/ui/union/union-unsafe.rs | 2 +- src/test/ui/union/union-unsafe.thir.stderr | 10 +------- 6 files changed, 14 insertions(+), 57 deletions(-) diff --git a/compiler/rustc_middle/src/mir/query.rs b/compiler/rustc_middle/src/mir/query.rs index 620f0380d53b7..6a6ed3dc728d9 100644 --- a/compiler/rustc_middle/src/mir/query.rs +++ b/compiler/rustc_middle/src/mir/query.rs @@ -35,7 +35,6 @@ pub enum UnsafetyViolationDetails { UseOfMutableStatic, UseOfExternStatic, DerefOfRawPointer, - AssignToDroppingUnionField, AccessToUnionField, MutationOfLayoutConstrainedField, BorrowOfLayoutConstrainedField, @@ -78,11 +77,6 @@ impl UnsafetyViolationDetails { "raw pointers may be null, dangling or unaligned; they can violate aliasing rules \ and cause data races: all of these are undefined behavior", ), - AssignToDroppingUnionField => ( - "assignment to union field that might need dropping", - "the previous content of the field will be dropped, which causes undefined \ - behavior if the field was not properly initialized", - ), AccessToUnionField => ( "access to union field", "the field may not be properly initialized: using uninitialized data will cause \ diff --git a/compiler/rustc_mir_build/src/check_unsafety.rs b/compiler/rustc_mir_build/src/check_unsafety.rs index 8585199faaf5a..54d3b7cdda62c 100644 --- a/compiler/rustc_mir_build/src/check_unsafety.rs +++ b/compiler/rustc_mir_build/src/check_unsafety.rs @@ -431,16 +431,9 @@ impl<'a, 'tcx> Visitor<'a, 'tcx> for UnsafetyVisitor<'a, 'tcx> { let lhs = &self.thir[lhs]; if let ty::Adt(adt_def, _) = lhs.ty.kind() && adt_def.is_union() { if let Some((assigned_ty, assignment_span)) = self.assignment_info { - // To avoid semver hazard, we only consider `Copy` and `ManuallyDrop` non-dropping. - if !(assigned_ty - .ty_adt_def() - .map_or(false, |adt| adt.is_manually_drop()) - || assigned_ty - .is_copy_modulo_regions(self.tcx.at(expr.span), self.param_env)) - { - self.requires_unsafe(assignment_span, AssignToDroppingUnionField); - } else { - // write to non-drop union field, safe + if assigned_ty.needs_drop(self.tcx, self.tcx.param_env(adt_def.did())) { + // This would be unsafe, but should be outright impossible since we reject such unions. + self.tcx.sess.delay_span_bug(assignment_span, "union fields that need dropping should be impossible"); } } else { self.requires_unsafe(expr.span, AccessToUnionField); @@ -537,7 +530,6 @@ enum UnsafeOpKind { UseOfMutableStatic, UseOfExternStatic, DerefOfRawPointer, - AssignToDroppingUnionField, AccessToUnionField, MutationOfLayoutConstrainedField, BorrowOfLayoutConstrainedField, @@ -555,7 +547,6 @@ impl UnsafeOpKind { UseOfMutableStatic => "use of mutable static", UseOfExternStatic => "use of extern static", DerefOfRawPointer => "dereference of raw pointer", - AssignToDroppingUnionField => "assignment to union field that might need dropping", AccessToUnionField => "access to union field", MutationOfLayoutConstrainedField => "mutation of layout constrained field", BorrowOfLayoutConstrainedField => { @@ -600,11 +591,6 @@ impl UnsafeOpKind { "raw pointers may be null, dangling or unaligned; they can violate aliasing rules \ and cause data races: all of these are undefined behavior", ), - AssignToDroppingUnionField => ( - Cow::Borrowed(self.simple_description()), - "the previous content of the field will be dropped, which causes undefined \ - behavior if the field was not properly initialized", - ), AccessToUnionField => ( Cow::Borrowed(self.simple_description()), "the field may not be properly initialized: using uninitialized data will cause \ diff --git a/compiler/rustc_mir_transform/src/check_unsafety.rs b/compiler/rustc_mir_transform/src/check_unsafety.rs index 1f73b7da815c5..ded1f0462cb01 100644 --- a/compiler/rustc_mir_transform/src/check_unsafety.rs +++ b/compiler/rustc_mir_transform/src/check_unsafety.rs @@ -219,22 +219,15 @@ impl<'tcx> Visitor<'tcx> for UnsafetyChecker<'_, 'tcx> { // We have to check the actual type of the assignment, as that determines if the // old value is being dropped. let assigned_ty = place.ty(&self.body.local_decls, self.tcx).ty; - // To avoid semver hazard, we only consider `Copy` and `ManuallyDrop` non-dropping. - let manually_drop = assigned_ty - .ty_adt_def() - .map_or(false, |adt_def| adt_def.is_manually_drop()); - let nodrop = manually_drop - || assigned_ty.is_copy_modulo_regions( - self.tcx.at(self.source_info.span), - self.param_env, + if assigned_ty.needs_drop( + self.tcx, + self.tcx.param_env(base_ty.ty_adt_def().unwrap().did()), + ) { + // This would be unsafe, but should be outright impossible since we reject such unions. + self.tcx.sess.delay_span_bug( + self.source_info.span, + "union fields that need dropping should be impossible", ); - if !nodrop { - self.require_unsafe( - UnsafetyViolationKind::General, - UnsafetyViolationDetails::AssignToDroppingUnionField, - ); - } else { - // write to non-drop union field, safe } } else { self.require_unsafe( diff --git a/src/test/ui/union/union-unsafe.mir.stderr b/src/test/ui/union/union-unsafe.mir.stderr index 0aefa21c94480..544213dbc5543 100644 --- a/src/test/ui/union/union-unsafe.mir.stderr +++ b/src/test/ui/union/union-unsafe.mir.stderr @@ -6,14 +6,6 @@ LL | *(u.p) = 13; | = note: the field may not be properly initialized: using uninitialized data will cause undefined behavior -error[E0133]: assignment to union field that might need dropping is unsafe and requires unsafe function or block - --> $DIR/union-unsafe.rs:38:5 - | -LL | u.a = (ManuallyDrop::new(RefCell::new(0)), 1); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ assignment to union field that might need dropping - | - = note: the previous content of the field will be dropped, which causes undefined behavior if the field was not properly initialized - error[E0133]: access to union field is unsafe and requires unsafe function or block --> $DIR/union-unsafe.rs:46:6 | @@ -78,6 +70,6 @@ LL | *u3.a = String::from("new"); | = note: the field may not be properly initialized: using uninitialized data will cause undefined behavior -error: aborting due to 10 previous errors +error: aborting due to 9 previous errors For more information about this error, try `rustc --explain E0133`. diff --git a/src/test/ui/union/union-unsafe.rs b/src/test/ui/union/union-unsafe.rs index 7e9d9052a6723..5e1837a901d46 100644 --- a/src/test/ui/union/union-unsafe.rs +++ b/src/test/ui/union/union-unsafe.rs @@ -35,7 +35,7 @@ fn deref_union_field(mut u: URef) { fn assign_noncopy_union_field(mut u: URefCell) { // FIXME(thir-unsafeck) - u.a = (ManuallyDrop::new(RefCell::new(0)), 1); //~ ERROR assignment to union field + u.a = (ManuallyDrop::new(RefCell::new(0)), 1); // OK (assignment does not drop) u.a.0 = ManuallyDrop::new(RefCell::new(0)); // OK (assignment does not drop) u.a.1 = 1; // OK } diff --git a/src/test/ui/union/union-unsafe.thir.stderr b/src/test/ui/union/union-unsafe.thir.stderr index dbfd92f05d951..f959fe5bdb5c5 100644 --- a/src/test/ui/union/union-unsafe.thir.stderr +++ b/src/test/ui/union/union-unsafe.thir.stderr @@ -6,14 +6,6 @@ LL | *(u.p) = 13; | = note: the field may not be properly initialized: using uninitialized data will cause undefined behavior -error[E0133]: assignment to union field that might need dropping is unsafe and requires unsafe function or block - --> $DIR/union-unsafe.rs:38:5 - | -LL | u.a = (ManuallyDrop::new(RefCell::new(0)), 1); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ assignment to union field that might need dropping - | - = note: the previous content of the field will be dropped, which causes undefined behavior if the field was not properly initialized - error[E0133]: access to union field is unsafe and requires unsafe function or block --> $DIR/union-unsafe.rs:46:6 | @@ -78,6 +70,6 @@ LL | *u3.a = String::from("new"); | = note: the field may not be properly initialized: using uninitialized data will cause undefined behavior -error: aborting due to 10 previous errors +error: aborting due to 9 previous errors For more information about this error, try `rustc --explain E0133`. From d935c70afa464dcf16db532e39ae53621debd096 Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Mon, 11 Jul 2022 14:16:14 +0000 Subject: [PATCH 19/29] Don't allow accidental runtime-checks --- src/test/ui/layout/unsafe-cell-hides-niche.rs | 101 +++++++++--------- 1 file changed, 50 insertions(+), 51 deletions(-) diff --git a/src/test/ui/layout/unsafe-cell-hides-niche.rs b/src/test/ui/layout/unsafe-cell-hides-niche.rs index 1d0e1fce178d0..865fc2ae29702 100644 --- a/src/test/ui/layout/unsafe-cell-hides-niche.rs +++ b/src/test/ui/layout/unsafe-cell-hides-niche.rs @@ -4,6 +4,7 @@ // size in memory as an `Option>` (namely, 8 bytes). // check-pass +// compile-flags: --crate-type=lib #![feature(repr_simd)] @@ -23,59 +24,57 @@ struct Size; // Overwriting the runtime assertion and making it a compile-time assertion macro_rules! assert_size { - ($a:ty, $b:expr) => {{ + ($a:ty, $b:expr) => { const _: Size::<{$b}> = Size::<{size_of::<$a>()}>; - }}; + }; } const PTR_SIZE: usize = std::mem::size_of::<*const ()>(); -fn main() { - assert_size!(Option>, 8); - assert_size!(Option>, 4); // (✓ niche opt) - assert_size!(Option>, 8); - assert_size!(Option>, 4); // (✓ niche opt) - assert_size!(Option>, 8); - assert_size!(Option>, 8); // (✗ niche opt) - - assert_size!(Option>, 8); - assert_size!(Option>, 8); // (✗ niche opt) - - assert_size!( UnsafeCell<&()> , PTR_SIZE); - assert_size!(Option>, PTR_SIZE * 2); // (✗ niche opt) - assert_size!( Cell<&()> , PTR_SIZE); - assert_size!(Option< Cell<&()>>, PTR_SIZE * 2); // (✗ niche opt) - assert_size!( RefCell<&()> , PTR_SIZE * 2); - assert_size!(Option< RefCell<&()>>, PTR_SIZE * 3); // (✗ niche opt) - assert_size!( - RwLock<&()>, - if cfg!(target_pointer_width = "32") { 16 } else { 24 } - ); - assert_size!( - Option>, - if cfg!(target_pointer_width = "32") { 20 } else { 32 } - ); // (✗ niche opt) - assert_size!( - Mutex<&()> , - if cfg!(target_pointer_width = "32") { 12 } else { 16 } - ); - assert_size!( - Option>, - if cfg!(target_pointer_width = "32") { 16 } else { 24 } - ); // (✗ niche opt) - - assert_size!( UnsafeCell<&[i32]> , PTR_SIZE * 2); - assert_size!(Option>, PTR_SIZE * 3); // (✗ niche opt) - assert_size!( UnsafeCell<(&(), &())> , PTR_SIZE * 2); - assert_size!(Option>, PTR_SIZE * 3); // (✗ niche opt) - - trait Trait {} - assert_size!( UnsafeCell<&dyn Trait> , PTR_SIZE * 2); - assert_size!(Option>, PTR_SIZE * 3); // (✗ niche opt) - - #[repr(simd)] - pub struct Vec4([T; 4]); - - assert_size!( UnsafeCell> , 16); - assert_size!(Option>>, 32); // (✗ niche opt) -} +assert_size!(Option>, 8); +assert_size!(Option>, 4); // (✓ niche opt) +assert_size!(Option>, 8); +assert_size!(Option>, 4); // (✓ niche opt) +assert_size!(Option>, 8); +assert_size!(Option>, 8); // (✗ niche opt) + +assert_size!(Option>, 8); +assert_size!(Option>, 8); // (✗ niche opt) + +assert_size!( UnsafeCell<&()> , PTR_SIZE); +assert_size!(Option>, PTR_SIZE * 2); // (✗ niche opt) +assert_size!( Cell<&()> , PTR_SIZE); +assert_size!(Option< Cell<&()>>, PTR_SIZE * 2); // (✗ niche opt) +assert_size!( RefCell<&()> , PTR_SIZE * 2); +assert_size!(Option< RefCell<&()>>, PTR_SIZE * 3); // (✗ niche opt) +assert_size!( + RwLock<&()>, + if cfg!(target_pointer_width = "32") { 16 } else { 24 } +); +assert_size!( + Option>, + if cfg!(target_pointer_width = "32") { 20 } else { 32 } +); // (✗ niche opt) +assert_size!( + Mutex<&()> , + if cfg!(target_pointer_width = "32") { 12 } else { 16 } +); +assert_size!( + Option>, + if cfg!(target_pointer_width = "32") { 16 } else { 24 } +); // (✗ niche opt) + +assert_size!( UnsafeCell<&[i32]> , PTR_SIZE * 2); +assert_size!(Option>, PTR_SIZE * 3); // (✗ niche opt) +assert_size!( UnsafeCell<(&(), &())> , PTR_SIZE * 2); +assert_size!(Option>, PTR_SIZE * 3); // (✗ niche opt) + +trait Trait {} +assert_size!( UnsafeCell<&dyn Trait> , PTR_SIZE * 2); +assert_size!(Option>, PTR_SIZE * 3); // (✗ niche opt) + +#[repr(simd)] +pub struct Vec4([T; 4]); + +assert_size!( UnsafeCell> , 16); +assert_size!(Option>>, 32); // (✗ niche opt) From cdd6bba8f662b25d52a58d5ffebbe5c3eac60220 Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Mon, 11 Jul 2022 14:23:32 +0000 Subject: [PATCH 20/29] Simplify size checking --- src/test/ui/layout/unsafe-cell-hides-niche.rs | 70 ++++++++----------- 1 file changed, 31 insertions(+), 39 deletions(-) diff --git a/src/test/ui/layout/unsafe-cell-hides-niche.rs b/src/test/ui/layout/unsafe-cell-hides-niche.rs index 865fc2ae29702..9e80a708f2fd7 100644 --- a/src/test/ui/layout/unsafe-cell-hides-niche.rs +++ b/src/test/ui/layout/unsafe-cell-hides-niche.rs @@ -23,58 +23,50 @@ struct NoNiche(UnsafeCell); struct Size; // Overwriting the runtime assertion and making it a compile-time assertion -macro_rules! assert_size { - ($a:ty, $b:expr) => { - const _: Size::<{$b}> = Size::<{size_of::<$a>()}>; +macro_rules! assert_size_eq { + ($ty:ty, $size:expr) => { + const _: Size::<{$size}> = Size::<{size_of::<$ty>()}>; + }; + ($ty:ty, $size:expr, $optioned_size:expr) => { + assert_size_eq!($ty, $size); + assert_size_eq!(Option<$ty>, $optioned_size); + const _: () = assert!($size == $optioned_size || size_of::<$ty>() < size_of::>()); }; } const PTR_SIZE: usize = std::mem::size_of::<*const ()>(); -assert_size!(Option>, 8); -assert_size!(Option>, 4); // (✓ niche opt) -assert_size!(Option>, 8); -assert_size!(Option>, 4); // (✓ niche opt) -assert_size!(Option>, 8); -assert_size!(Option>, 8); // (✗ niche opt) - -assert_size!(Option>, 8); -assert_size!(Option>, 8); // (✗ niche opt) - -assert_size!( UnsafeCell<&()> , PTR_SIZE); -assert_size!(Option>, PTR_SIZE * 2); // (✗ niche opt) -assert_size!( Cell<&()> , PTR_SIZE); -assert_size!(Option< Cell<&()>>, PTR_SIZE * 2); // (✗ niche opt) -assert_size!( RefCell<&()> , PTR_SIZE * 2); -assert_size!(Option< RefCell<&()>>, PTR_SIZE * 3); // (✗ niche opt) -assert_size!( +assert_size_eq!(Wrapper, 4, 8); +assert_size_eq!(Wrapper, 4, 4); // (✓ niche opt) +assert_size_eq!(Transparent, 4, 8); +assert_size_eq!(Transparent, 4, 4); // (✓ niche opt) +assert_size_eq!(NoNiche, 4, 8); +assert_size_eq!(NoNiche, 4, 8); + +assert_size_eq!(UnsafeCell, 4, 8); +assert_size_eq!(UnsafeCell, 4, 8); + +assert_size_eq!(UnsafeCell<&()> , PTR_SIZE, PTR_SIZE * 2); +assert_size_eq!( Cell<&()> , PTR_SIZE, PTR_SIZE * 2); +assert_size_eq!( RefCell<&()> , PTR_SIZE * 2, PTR_SIZE * 3); +assert_size_eq!( RwLock<&()>, - if cfg!(target_pointer_width = "32") { 16 } else { 24 } -); -assert_size!( - Option>, + if cfg!(target_pointer_width = "32") { 16 } else { 24 }, if cfg!(target_pointer_width = "32") { 20 } else { 32 } -); // (✗ niche opt) -assert_size!( - Mutex<&()> , - if cfg!(target_pointer_width = "32") { 12 } else { 16 } ); -assert_size!( - Option>, +assert_size_eq!( + Mutex<&()> , + if cfg!(target_pointer_width = "32") { 12 } else { 16 }, if cfg!(target_pointer_width = "32") { 16 } else { 24 } -); // (✗ niche opt) +); -assert_size!( UnsafeCell<&[i32]> , PTR_SIZE * 2); -assert_size!(Option>, PTR_SIZE * 3); // (✗ niche opt) -assert_size!( UnsafeCell<(&(), &())> , PTR_SIZE * 2); -assert_size!(Option>, PTR_SIZE * 3); // (✗ niche opt) +assert_size_eq!(UnsafeCell<&[i32]> , PTR_SIZE * 2, PTR_SIZE * 3); +assert_size_eq!(UnsafeCell<(&(), &())> , PTR_SIZE * 2, PTR_SIZE * 3); trait Trait {} -assert_size!( UnsafeCell<&dyn Trait> , PTR_SIZE * 2); -assert_size!(Option>, PTR_SIZE * 3); // (✗ niche opt) +assert_size_eq!(UnsafeCell<&dyn Trait> , PTR_SIZE * 2, PTR_SIZE * 3); #[repr(simd)] pub struct Vec4([T; 4]); -assert_size!( UnsafeCell> , 16); -assert_size!(Option>>, 32); // (✗ niche opt) +assert_size_eq!(UnsafeCell> , 16, 32); From 0318b70514e13d09fd0e9043da4b7c49e0285f75 Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Mon, 11 Jul 2022 14:35:04 +0000 Subject: [PATCH 21/29] tidy --- src/test/ui/layout/unsafe-cell-hides-niche.rs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/test/ui/layout/unsafe-cell-hides-niche.rs b/src/test/ui/layout/unsafe-cell-hides-niche.rs index 9e80a708f2fd7..7f159887ba1d4 100644 --- a/src/test/ui/layout/unsafe-cell-hides-niche.rs +++ b/src/test/ui/layout/unsafe-cell-hides-niche.rs @@ -30,7 +30,10 @@ macro_rules! assert_size_eq { ($ty:ty, $size:expr, $optioned_size:expr) => { assert_size_eq!($ty, $size); assert_size_eq!(Option<$ty>, $optioned_size); - const _: () = assert!($size == $optioned_size || size_of::<$ty>() < size_of::>()); + const _: () = assert!( + $size == $optioned_size || + size_of::<$ty>() < size_of::>() + ); }; } From 7a24f8ee27b9b367606bf23334302a0b257e46ff Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 30 Jun 2022 10:17:49 -0400 Subject: [PATCH 22/29] add array tests, cleanup, tidy, and bless --- compiler/rustc_feature/src/removed.rs | 2 +- compiler/rustc_typeck/src/check/check.rs | 2 +- compiler/rustc_typeck/src/lib.rs | 1 + src/test/ui/consts/invalid-union.32bit.stderr | 6 ++--- src/test/ui/union/field_checks.rs | 10 ++++++++- src/test/ui/union/field_checks.stderr | 22 ++++++++++++++----- src/test/ui/union/union-nonrepresentable.rs | 1 - .../ui/union/union-nonrepresentable.stderr | 2 +- 8 files changed, 33 insertions(+), 13 deletions(-) diff --git a/compiler/rustc_feature/src/removed.rs b/compiler/rustc_feature/src/removed.rs index 3b0f9a65e07f3..2ddaf9201098e 100644 --- a/compiler/rustc_feature/src/removed.rs +++ b/compiler/rustc_feature/src/removed.rs @@ -182,7 +182,7 @@ declare_features! ( (removed, unsafe_no_drop_flag, "1.0.0", None, None, None), /// Allows `union` fields that don't implement `Copy` as long as they don't have any drop glue. (removed, untagged_unions, "1.13.0", Some(55149), None, - Some("unions with `Copy` and `MaybeUninit` fields are stable; there is no intent to stabilize more")), + Some("unions with `Copy` and `ManuallyDrop` fields are stable; there is no intent to stabilize more")), /// Allows `#[unwind(..)]`. /// /// Permits specifying whether a function should permit unwinding or abort on unwind. diff --git a/compiler/rustc_typeck/src/check/check.rs b/compiler/rustc_typeck/src/check/check.rs index 209842f658540..c56a5045ad4dd 100644 --- a/compiler/rustc_typeck/src/check/check.rs +++ b/compiler/rustc_typeck/src/check/check.rs @@ -421,7 +421,7 @@ fn check_union_fields(tcx: TyCtxt<'_>, span: Span, item_def_id: LocalDefId) -> b } _ => { // Fallback case: allow `ManuallyDrop` and things that are `Copy`. - ty.ty_adt_def().map_or(false, |adt_def| adt_def.is_manually_drop()) + ty.ty_adt_def().is_some_and(|adt_def| adt_def.is_manually_drop()) || ty.is_copy_modulo_regions(tcx.at(span), param_env) } } diff --git a/compiler/rustc_typeck/src/lib.rs b/compiler/rustc_typeck/src/lib.rs index 08c194ec0b605..1ee732628a7b1 100644 --- a/compiler/rustc_typeck/src/lib.rs +++ b/compiler/rustc_typeck/src/lib.rs @@ -72,6 +72,7 @@ This API is completely unstable and subject to change. #![feature(once_cell)] #![feature(slice_partition_dedup)] #![feature(try_blocks)] +#![feature(is_some_with)] #![recursion_limit = "256"] #[macro_use] diff --git a/src/test/ui/consts/invalid-union.32bit.stderr b/src/test/ui/consts/invalid-union.32bit.stderr index 7e9abc3ffa7e1..ae5f6b2baee40 100644 --- a/src/test/ui/consts/invalid-union.32bit.stderr +++ b/src/test/ui/consts/invalid-union.32bit.stderr @@ -1,5 +1,5 @@ error[E0080]: it is undefined behavior to use this value - --> $DIR/invalid-union.rs:40:1 + --> $DIR/invalid-union.rs:41:1 | LL | fn main() { | ^^^^^^^^^ constructing invalid value at ..y..0: encountered `UnsafeCell` in a `const` @@ -10,7 +10,7 @@ LL | fn main() { } error: erroneous constant used - --> $DIR/invalid-union.rs:41:25 + --> $DIR/invalid-union.rs:42:25 | LL | let _: &'static _ = &C; | ^^ referenced constant has errors @@ -24,7 +24,7 @@ error: aborting due to 2 previous errors For more information about this error, try `rustc --explain E0080`. Future incompatibility report: Future breakage diagnostic: error: erroneous constant used - --> $DIR/invalid-union.rs:41:25 + --> $DIR/invalid-union.rs:42:25 | LL | let _: &'static _ = &C; | ^^ referenced constant has errors diff --git a/src/test/ui/union/field_checks.rs b/src/test/ui/union/field_checks.rs index 216f7372a1cff..d5d1e44ac855c 100644 --- a/src/test/ui/union/field_checks.rs +++ b/src/test/ui/union/field_checks.rs @@ -1,4 +1,3 @@ -// ignore-tidy-linelength use std::mem::ManuallyDrop; union U1 { // OK @@ -45,6 +44,10 @@ union U5Nested { // a nested union that drops is NOT OK nest: U5, //~ ERROR unions cannot contain fields that may need dropping } +union U5Nested2 { // for now we don't special-case empty arrays + nest: [U5; 0], //~ ERROR unions cannot contain fields that may need dropping +} + union U6 { // OK s: &'static i32, m: &'static mut i32, @@ -54,4 +57,9 @@ union U7 { // OK f: (&'static mut i32, ManuallyDrop, i32), } +union U8 { // OK + f1: [(&'static mut i32, i32); 8], + f2: [ManuallyDrop; 2], +} + fn main() {} diff --git a/src/test/ui/union/field_checks.stderr b/src/test/ui/union/field_checks.stderr index 0e0e545b01a46..1f97e97ac6ede 100644 --- a/src/test/ui/union/field_checks.stderr +++ b/src/test/ui/union/field_checks.stderr @@ -1,5 +1,5 @@ error[E0740]: unions cannot contain fields that may need dropping - --> $DIR/field_checks.rs:25:5 + --> $DIR/field_checks.rs:24:5 | LL | a: String, | ^^^^^^^^^ @@ -11,7 +11,7 @@ LL | a: std::mem::ManuallyDrop, | +++++++++++++++++++++++ + error[E0740]: unions cannot contain fields that may need dropping - --> $DIR/field_checks.rs:29:5 + --> $DIR/field_checks.rs:28:5 | LL | a: std::cell::RefCell, | ^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -23,7 +23,7 @@ LL | a: std::mem::ManuallyDrop>, | +++++++++++++++++++++++ + error[E0740]: unions cannot contain fields that may need dropping - --> $DIR/field_checks.rs:33:5 + --> $DIR/field_checks.rs:32:5 | LL | a: T, | ^^^^ @@ -35,7 +35,7 @@ LL | a: std::mem::ManuallyDrop, | +++++++++++++++++++++++ + error[E0740]: unions cannot contain fields that may need dropping - --> $DIR/field_checks.rs:45:5 + --> $DIR/field_checks.rs:44:5 | LL | nest: U5, | ^^^^^^^^ @@ -46,6 +46,18 @@ help: when the type does not implement `Copy`, wrap it inside a `ManuallyDrop<_> LL | nest: std::mem::ManuallyDrop, | +++++++++++++++++++++++ + -error: aborting due to 4 previous errors +error[E0740]: unions cannot contain fields that may need dropping + --> $DIR/field_checks.rs:48:5 + | +LL | nest: [U5; 0], + | ^^^^^^^^^^^^^ + | + = note: a type is guaranteed not to need dropping when it implements `Copy`, or when it is the special `ManuallyDrop<_>` type +help: when the type does not implement `Copy`, wrap it inside a `ManuallyDrop<_>` and ensure it is manually dropped + | +LL | nest: std::mem::ManuallyDrop<[U5; 0]>, + | +++++++++++++++++++++++ + + +error: aborting due to 5 previous errors For more information about this error, try `rustc --explain E0740`. diff --git a/src/test/ui/union/union-nonrepresentable.rs b/src/test/ui/union/union-nonrepresentable.rs index afa73857ac2a5..4bdf7c6872fa5 100644 --- a/src/test/ui/union/union-nonrepresentable.rs +++ b/src/test/ui/union/union-nonrepresentable.rs @@ -1,4 +1,3 @@ - union U { //~ ERROR recursive type `U` has infinite size a: u8, b: std::mem::ManuallyDrop, diff --git a/src/test/ui/union/union-nonrepresentable.stderr b/src/test/ui/union/union-nonrepresentable.stderr index a2380d8bc0e99..9804b1418b208 100644 --- a/src/test/ui/union/union-nonrepresentable.stderr +++ b/src/test/ui/union/union-nonrepresentable.stderr @@ -1,5 +1,5 @@ error[E0072]: recursive type `U` has infinite size - --> $DIR/union-nonrepresentable.rs:2:1 + --> $DIR/union-nonrepresentable.rs:1:1 | LL | union U { | ^^^^^^^ recursive type has infinite size From 3338593afd6a010a2ce6799d3bf4bf4c2a252950 Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Mon, 11 Jul 2022 15:41:38 +0000 Subject: [PATCH 23/29] Only check relative sizes on platform specific types --- src/test/ui/layout/unsafe-cell-hides-niche.rs | 69 +++++++++---------- 1 file changed, 32 insertions(+), 37 deletions(-) diff --git a/src/test/ui/layout/unsafe-cell-hides-niche.rs b/src/test/ui/layout/unsafe-cell-hides-niche.rs index 7f159887ba1d4..9eed2ad361ce3 100644 --- a/src/test/ui/layout/unsafe-cell-hides-niche.rs +++ b/src/test/ui/layout/unsafe-cell-hides-niche.rs @@ -22,54 +22,49 @@ struct NoNiche(UnsafeCell); struct Size; -// Overwriting the runtime assertion and making it a compile-time assertion -macro_rules! assert_size_eq { - ($ty:ty, $size:expr) => { +macro_rules! check_sizes { + (check_one_specific_size: $ty:ty, $size:expr) => { const _: Size::<{$size}> = Size::<{size_of::<$ty>()}>; }; ($ty:ty, $size:expr, $optioned_size:expr) => { - assert_size_eq!($ty, $size); - assert_size_eq!(Option<$ty>, $optioned_size); - const _: () = assert!( - $size == $optioned_size || - size_of::<$ty>() < size_of::>() - ); + check_sizes!(check_one_specific_size: $ty, $size); + check_sizes!(check_one_specific_size: Option<$ty>, $optioned_size); + check_sizes!(check_no_niche_opt: $size != $optioned_size, $ty); + }; + ($ty:ty) => { + check_sizes!(check_no_niche_opt: true, $ty); + }; + (check_no_niche_opt: $no_niche_opt:expr, $ty:ty) => { + const _: () = if $no_niche_opt { assert!(size_of::<$ty>() < size_of::>()); }; }; } const PTR_SIZE: usize = std::mem::size_of::<*const ()>(); -assert_size_eq!(Wrapper, 4, 8); -assert_size_eq!(Wrapper, 4, 4); // (✓ niche opt) -assert_size_eq!(Transparent, 4, 8); -assert_size_eq!(Transparent, 4, 4); // (✓ niche opt) -assert_size_eq!(NoNiche, 4, 8); -assert_size_eq!(NoNiche, 4, 8); - -assert_size_eq!(UnsafeCell, 4, 8); -assert_size_eq!(UnsafeCell, 4, 8); - -assert_size_eq!(UnsafeCell<&()> , PTR_SIZE, PTR_SIZE * 2); -assert_size_eq!( Cell<&()> , PTR_SIZE, PTR_SIZE * 2); -assert_size_eq!( RefCell<&()> , PTR_SIZE * 2, PTR_SIZE * 3); -assert_size_eq!( - RwLock<&()>, - if cfg!(target_pointer_width = "32") { 16 } else { 24 }, - if cfg!(target_pointer_width = "32") { 20 } else { 32 } -); -assert_size_eq!( - Mutex<&()> , - if cfg!(target_pointer_width = "32") { 12 } else { 16 }, - if cfg!(target_pointer_width = "32") { 16 } else { 24 } -); - -assert_size_eq!(UnsafeCell<&[i32]> , PTR_SIZE * 2, PTR_SIZE * 3); -assert_size_eq!(UnsafeCell<(&(), &())> , PTR_SIZE * 2, PTR_SIZE * 3); +check_sizes!(Wrapper, 4, 8); +check_sizes!(Wrapper, 4, 4); // (✓ niche opt) +check_sizes!(Transparent, 4, 8); +check_sizes!(Transparent, 4, 4); // (✓ niche opt) +check_sizes!(NoNiche, 4, 8); +check_sizes!(NoNiche, 4, 8); + +check_sizes!(UnsafeCell, 4, 8); +check_sizes!(UnsafeCell, 4, 8); + +check_sizes!(UnsafeCell<&()> , PTR_SIZE, PTR_SIZE * 2); +check_sizes!( Cell<&()> , PTR_SIZE, PTR_SIZE * 2); +check_sizes!( RefCell<&()> , PTR_SIZE * 2, PTR_SIZE * 3); + +check_sizes!(RwLock<&()>); +check_sizes!(Mutex<&()>); + +check_sizes!(UnsafeCell<&[i32]> , PTR_SIZE * 2, PTR_SIZE * 3); +check_sizes!(UnsafeCell<(&(), &())> , PTR_SIZE * 2, PTR_SIZE * 3); trait Trait {} -assert_size_eq!(UnsafeCell<&dyn Trait> , PTR_SIZE * 2, PTR_SIZE * 3); +check_sizes!(UnsafeCell<&dyn Trait> , PTR_SIZE * 2, PTR_SIZE * 3); #[repr(simd)] pub struct Vec4([T; 4]); -assert_size_eq!(UnsafeCell> , 16, 32); +check_sizes!(UnsafeCell> , 16, 32); From 24e87965ae35843fe340a5104482be1d1f827af7 Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Tue, 12 Jul 2022 07:22:52 +0000 Subject: [PATCH 24/29] Use some more visible sigils than `,` --- src/test/ui/layout/unsafe-cell-hides-niche.rs | 32 +++++++++---------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/src/test/ui/layout/unsafe-cell-hides-niche.rs b/src/test/ui/layout/unsafe-cell-hides-niche.rs index 9eed2ad361ce3..e82eaa38612cd 100644 --- a/src/test/ui/layout/unsafe-cell-hides-niche.rs +++ b/src/test/ui/layout/unsafe-cell-hides-niche.rs @@ -26,7 +26,7 @@ macro_rules! check_sizes { (check_one_specific_size: $ty:ty, $size:expr) => { const _: Size::<{$size}> = Size::<{size_of::<$ty>()}>; }; - ($ty:ty, $size:expr, $optioned_size:expr) => { + ($ty:ty: $size:expr => $optioned_size:expr) => { check_sizes!(check_one_specific_size: $ty, $size); check_sizes!(check_one_specific_size: Option<$ty>, $optioned_size); check_sizes!(check_no_niche_opt: $size != $optioned_size, $ty); @@ -41,30 +41,30 @@ macro_rules! check_sizes { const PTR_SIZE: usize = std::mem::size_of::<*const ()>(); -check_sizes!(Wrapper, 4, 8); -check_sizes!(Wrapper, 4, 4); // (✓ niche opt) -check_sizes!(Transparent, 4, 8); -check_sizes!(Transparent, 4, 4); // (✓ niche opt) -check_sizes!(NoNiche, 4, 8); -check_sizes!(NoNiche, 4, 8); +check_sizes!(Wrapper: 4 => 8); +check_sizes!(Wrapper: 4 => 4); // (✓ niche opt) +check_sizes!(Transparent: 4 => 8); +check_sizes!(Transparent: 4 => 4); // (✓ niche opt) +check_sizes!(NoNiche: 4 => 8); +check_sizes!(NoNiche: 4 => 8); -check_sizes!(UnsafeCell, 4, 8); -check_sizes!(UnsafeCell, 4, 8); +check_sizes!(UnsafeCell: 4 => 8); +check_sizes!(UnsafeCell: 4 => 8); -check_sizes!(UnsafeCell<&()> , PTR_SIZE, PTR_SIZE * 2); -check_sizes!( Cell<&()> , PTR_SIZE, PTR_SIZE * 2); -check_sizes!( RefCell<&()> , PTR_SIZE * 2, PTR_SIZE * 3); +check_sizes!(UnsafeCell<&()>: PTR_SIZE => PTR_SIZE * 2); +check_sizes!( Cell<&()>: PTR_SIZE => PTR_SIZE * 2); +check_sizes!( RefCell<&()>: PTR_SIZE * 2 => PTR_SIZE * 3); check_sizes!(RwLock<&()>); check_sizes!(Mutex<&()>); -check_sizes!(UnsafeCell<&[i32]> , PTR_SIZE * 2, PTR_SIZE * 3); -check_sizes!(UnsafeCell<(&(), &())> , PTR_SIZE * 2, PTR_SIZE * 3); +check_sizes!(UnsafeCell<&[i32]>: PTR_SIZE * 2 => PTR_SIZE * 3); +check_sizes!(UnsafeCell<(&(), &())>: PTR_SIZE * 2 => PTR_SIZE * 3); trait Trait {} -check_sizes!(UnsafeCell<&dyn Trait> , PTR_SIZE * 2, PTR_SIZE * 3); +check_sizes!(UnsafeCell<&dyn Trait>: PTR_SIZE * 2 => PTR_SIZE * 3); #[repr(simd)] pub struct Vec4([T; 4]); -check_sizes!(UnsafeCell> , 16, 32); +check_sizes!(UnsafeCell>: 16 => 32); From 726919629e0ca3660a41843f9565469e5dd2b2d9 Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Tue, 12 Jul 2022 07:29:36 +0000 Subject: [PATCH 25/29] Always check Cell alongside with `UnsafeCell` --- src/test/ui/layout/unsafe-cell-hides-niche.rs | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/src/test/ui/layout/unsafe-cell-hides-niche.rs b/src/test/ui/layout/unsafe-cell-hides-niche.rs index e82eaa38612cd..fce101d7bb173 100644 --- a/src/test/ui/layout/unsafe-cell-hides-niche.rs +++ b/src/test/ui/layout/unsafe-cell-hides-niche.rs @@ -26,11 +26,23 @@ macro_rules! check_sizes { (check_one_specific_size: $ty:ty, $size:expr) => { const _: Size::<{$size}> = Size::<{size_of::<$ty>()}>; }; + // Any tests run on `UnsafeCell` must be the same for `Cell` + (UnsafeCell<$ty:ty>: $size:expr => $optioned_size:expr) => { + check_sizes!(Cell<$ty>: $size => $optioned_size); + check_sizes!(@actual_check: UnsafeCell<$ty>: $size => $optioned_size); + }; ($ty:ty: $size:expr => $optioned_size:expr) => { + check_sizes!(@actual_check: $ty: $size => $optioned_size); + }; + // This branch does the actual checking logic, the `@actual_check` prefix is here to distinguish + // it from other branches and not accidentally match any. + (@actual_check: $ty:ty: $size:expr => $optioned_size:expr) => { check_sizes!(check_one_specific_size: $ty, $size); check_sizes!(check_one_specific_size: Option<$ty>, $optioned_size); check_sizes!(check_no_niche_opt: $size != $optioned_size, $ty); }; + // only check that there is no niche (size goes up when wrapped in an option), + // don't check actual sizes ($ty:ty) => { check_sizes!(check_no_niche_opt: true, $ty); }; @@ -52,7 +64,6 @@ check_sizes!(UnsafeCell: 4 => 8); check_sizes!(UnsafeCell: 4 => 8); check_sizes!(UnsafeCell<&()>: PTR_SIZE => PTR_SIZE * 2); -check_sizes!( Cell<&()>: PTR_SIZE => PTR_SIZE * 2); check_sizes!( RefCell<&()>: PTR_SIZE * 2 => PTR_SIZE * 3); check_sizes!(RwLock<&()>); From 944c0e23b8e44782e5097a7265bd78d124b92523 Mon Sep 17 00:00:00 2001 From: Deadbeef Date: Thu, 7 Jul 2022 16:55:41 +0000 Subject: [PATCH 26/29] check non_exhaustive attr and private fields for transparent types --- compiler/rustc_lint_defs/src/builtin.rs | 51 +++++++++++++ compiler/rustc_typeck/src/check/check.rs | 71 +++++++++++++++++-- .../repr-transparent-non-exhaustive.rs | 10 +++ .../repr/repr-transparent-non-exhaustive.rs | 60 ++++++++++++++++ .../repr-transparent-non-exhaustive.stderr | 67 +++++++++++++++++ 5 files changed, 254 insertions(+), 5 deletions(-) create mode 100644 src/test/ui/repr/auxiliary/repr-transparent-non-exhaustive.rs create mode 100644 src/test/ui/repr/repr-transparent-non-exhaustive.rs create mode 100644 src/test/ui/repr/repr-transparent-non-exhaustive.stderr diff --git a/compiler/rustc_lint_defs/src/builtin.rs b/compiler/rustc_lint_defs/src/builtin.rs index 9fc2249b29019..ae973e6a56382 100644 --- a/compiler/rustc_lint_defs/src/builtin.rs +++ b/compiler/rustc_lint_defs/src/builtin.rs @@ -3132,6 +3132,56 @@ declare_lint! { "detects unexpected names and values in `#[cfg]` conditions", } +declare_lint! { + /// The `repr_transparent_external_private_fields` lint + /// detects types marked #[repr(trasparent)] that (transitively) + /// contain an external ZST type marked #[non_exhaustive] + /// + /// ### Example + /// + /// ```rust,ignore (needs external crate) + /// #![deny(repr_transparent_external_private_fields)] + /// use foo::NonExhaustiveZst; + /// + /// #[repr(transparent)] + /// struct Bar(u32, ([u32; 0], NonExhaustiveZst)); + /// ``` + /// + /// This will produce: + /// + /// ```text + /// error: deprecated `#[macro_use]` attribute used to import macros should be replaced at use sites with a `use` item to import the macro instead + /// --> src/main.rs:3:1 + /// | + /// 3 | #[macro_use] + /// | ^^^^^^^^^^^^ + /// | + /// note: the lint level is defined here + /// --> src/main.rs:1:9 + /// | + /// 1 | #![deny(repr_transparent_external_private_fields)] + /// | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + /// ``` + /// + /// ### Explanation + /// + /// Previous, Rust accepted fields that contain external private zero-sized types, + /// even though it should not be a breaking change to add a non-zero-sized field to + /// that private type. + /// + /// This is a [future-incompatible] lint to transition this + /// to a hard error in the future. See [issue #78586] for more details. + /// + /// [issue #78586]: https://github.com/rust-lang/rust/issues/78586 + /// [future-incompatible]: ../index.md#future-incompatible-lints + pub REPR_TRANSPARENT_EXTERNAL_PRIVATE_FIELDS, + Warn, + "tranparent type contains an external ZST that is marked #[non_exhaustive] or contains private fields", + @future_incompatible = FutureIncompatibleInfo { + reference: "issue #78586 ", + }; +} + declare_lint_pass! { /// Does nothing as a lint pass, but registers some `Lint`s /// that are used by other parts of the compiler. @@ -3237,6 +3287,7 @@ declare_lint_pass! { DEPRECATED_WHERE_CLAUSE_LOCATION, TEST_UNSTABLE_LINT, FFI_UNWIND_CALLS, + REPR_TRANSPARENT_EXTERNAL_PRIVATE_FIELDS, ] } diff --git a/compiler/rustc_typeck/src/check/check.rs b/compiler/rustc_typeck/src/check/check.rs index e9709b64d930e..79edbeab9c72e 100644 --- a/compiler/rustc_typeck/src/check/check.rs +++ b/compiler/rustc_typeck/src/check/check.rs @@ -17,6 +17,7 @@ use rustc_infer::infer::outlives::env::OutlivesEnvironment; use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind}; use rustc_infer::infer::{RegionVariableOrigin, TyCtxtInferExt}; use rustc_infer::traits::Obligation; +use rustc_lint::builtin::REPR_TRANSPARENT_EXTERNAL_PRIVATE_FIELDS; use rustc_middle::hir::nested_filter; use rustc_middle::ty::layout::{LayoutError, MAX_SIMD_LANES}; use rustc_middle::ty::subst::GenericArgKind; @@ -1318,7 +1319,8 @@ pub(super) fn check_transparent<'tcx>(tcx: TyCtxt<'tcx>, sp: Span, adt: ty::AdtD } } - // For each field, figure out if it's known to be a ZST and align(1) + // For each field, figure out if it's known to be a ZST and align(1), with "known" + // respecting #[non_exhaustive] attributes. let field_infos = adt.all_fields().map(|field| { let ty = field.ty(tcx, InternalSubsts::identity_for_item(tcx, field.did)); let param_env = tcx.param_env(field.did); @@ -1327,16 +1329,56 @@ pub(super) fn check_transparent<'tcx>(tcx: TyCtxt<'tcx>, sp: Span, adt: ty::AdtD let span = tcx.hir().span_if_local(field.did).unwrap(); let zst = layout.map_or(false, |layout| layout.is_zst()); let align1 = layout.map_or(false, |layout| layout.align.abi.bytes() == 1); - (span, zst, align1) + if !zst { + return (span, zst, align1, None); + } + + fn check_non_exhaustive<'tcx>( + tcx: TyCtxt<'tcx>, + t: Ty<'tcx>, + ) -> ControlFlow<(&'static str, DefId, SubstsRef<'tcx>, bool)> { + match t.kind() { + ty::Tuple(list) => list.iter().try_for_each(|t| check_non_exhaustive(tcx, t)), + ty::Array(ty, _) => check_non_exhaustive(tcx, *ty), + ty::Adt(def, subst) => { + if !def.did().is_local() { + let non_exhaustive = def.is_variant_list_non_exhaustive() + || def + .variants() + .iter() + .any(ty::VariantDef::is_field_list_non_exhaustive); + let has_priv = def.all_fields().any(|f| !f.vis.is_public()); + if non_exhaustive || has_priv { + return ControlFlow::Break(( + def.descr(), + def.did(), + subst, + non_exhaustive, + )); + } + } + def.all_fields() + .map(|field| field.ty(tcx, subst)) + .try_for_each(|t| check_non_exhaustive(tcx, t)) + } + _ => ControlFlow::Continue(()), + } + } + + (span, zst, align1, check_non_exhaustive(tcx, ty).break_value()) }); - let non_zst_fields = - field_infos.clone().filter_map(|(span, zst, _align1)| if !zst { Some(span) } else { None }); + let non_zst_fields = field_infos + .clone() + .filter_map(|(span, zst, _align1, _non_exhaustive)| if !zst { Some(span) } else { None }); let non_zst_count = non_zst_fields.clone().count(); if non_zst_count >= 2 { bad_non_zero_sized_fields(tcx, adt, non_zst_count, non_zst_fields, sp); } - for (span, zst, align1) in field_infos { + let incompatible_zst_fields = + field_infos.clone().filter(|(_, _, _, opt)| opt.is_some()).count(); + let incompat = incompatible_zst_fields + non_zst_count >= 2 && non_zst_count < 2; + for (span, zst, align1, non_exhaustive) in field_infos { if zst && !align1 { struct_span_err!( tcx.sess, @@ -1348,6 +1390,25 @@ pub(super) fn check_transparent<'tcx>(tcx: TyCtxt<'tcx>, sp: Span, adt: ty::AdtD .span_label(span, "has alignment larger than 1") .emit(); } + if incompat && let Some((descr, def_id, substs, non_exhaustive)) = non_exhaustive { + tcx.struct_span_lint_hir( + REPR_TRANSPARENT_EXTERNAL_PRIVATE_FIELDS, + tcx.hir().local_def_id_to_hir_id(adt.did().expect_local()), + span, + |lint| { + let note = if non_exhaustive { + "is marked with `#[non_exhaustive]`" + } else { + "contains private fields" + }; + let field_ty = tcx.def_path_str_with_substs(def_id, substs); + lint.build("zero-sized fields in repr(transparent) cannot contain external non-exhaustive types") + .note(format!("this {descr} contains `{field_ty}`, which {note}, \ + and makes it not a breaking change to become non-zero-sized in the future.")) + .emit(); + }, + ) + } } } diff --git a/src/test/ui/repr/auxiliary/repr-transparent-non-exhaustive.rs b/src/test/ui/repr/auxiliary/repr-transparent-non-exhaustive.rs new file mode 100644 index 0000000000000..b8ae5c2b729fd --- /dev/null +++ b/src/test/ui/repr/auxiliary/repr-transparent-non-exhaustive.rs @@ -0,0 +1,10 @@ +#![crate_type = "lib"] + +pub struct Private { _priv: () } + +#[non_exhaustive] +pub struct NonExhaustive {} + +pub struct ExternalIndirection { + pub x: T, +} diff --git a/src/test/ui/repr/repr-transparent-non-exhaustive.rs b/src/test/ui/repr/repr-transparent-non-exhaustive.rs new file mode 100644 index 0000000000000..600caee8ba3a4 --- /dev/null +++ b/src/test/ui/repr/repr-transparent-non-exhaustive.rs @@ -0,0 +1,60 @@ +#![deny(repr_transparent_external_private_fields)] + +// aux-build: repr-transparent-non-exhaustive.rs +extern crate repr_transparent_non_exhaustive; + +use repr_transparent_non_exhaustive::{Private, NonExhaustive, ExternalIndirection}; + +pub struct InternalPrivate { + _priv: (), +} + +#[non_exhaustive] +pub struct InternalNonExhaustive; + +pub struct InternalIndirection { + x: T, +} + +pub type Sized = i32; + +#[repr(transparent)] +pub struct T1(Sized, InternalPrivate); +#[repr(transparent)] +pub struct T2(Sized, InternalNonExhaustive); +#[repr(transparent)] +pub struct T3(Sized, InternalIndirection<(InternalPrivate, InternalNonExhaustive)>); +#[repr(transparent)] +pub struct T4(Sized, ExternalIndirection<(InternalPrivate, InternalNonExhaustive)>); + +#[repr(transparent)] +pub struct T5(Sized, Private); +//~^ ERROR zero-sized fields in repr(transparent) cannot contain external non-exhaustive types +//~| WARN this was previously accepted by the compiler + +#[repr(transparent)] +pub struct T6(Sized, NonExhaustive); +//~^ ERROR zero-sized fields in repr(transparent) cannot contain external non-exhaustive types +//~| WARN this was previously accepted by the compiler + +#[repr(transparent)] +pub struct T7(Sized, InternalIndirection); +//~^ ERROR zero-sized fields in repr(transparent) cannot contain external non-exhaustive types +//~| WARN this was previously accepted by the compiler + +#[repr(transparent)] +pub struct T8(Sized, InternalIndirection); +//~^ ERROR zero-sized fields in repr(transparent) cannot contain external non-exhaustive types +//~| WARN this was previously accepted by the compiler + +#[repr(transparent)] +pub struct T9(Sized, ExternalIndirection); +//~^ ERROR zero-sized fields in repr(transparent) cannot contain external non-exhaustive types +//~| WARN this was previously accepted by the compiler + +#[repr(transparent)] +pub struct T10(Sized, ExternalIndirection); +//~^ ERROR zero-sized fields in repr(transparent) cannot contain external non-exhaustive types +//~| WARN this was previously accepted by the compiler + +fn main() {} diff --git a/src/test/ui/repr/repr-transparent-non-exhaustive.stderr b/src/test/ui/repr/repr-transparent-non-exhaustive.stderr new file mode 100644 index 0000000000000..3e45b2ab22cd5 --- /dev/null +++ b/src/test/ui/repr/repr-transparent-non-exhaustive.stderr @@ -0,0 +1,67 @@ +error: zero-sized fields in repr(transparent) cannot contain external non-exhaustive types + --> $DIR/repr-transparent-non-exhaustive.rs:31:22 + | +LL | pub struct T5(Sized, Private); + | ^^^^^^^ + | +note: the lint level is defined here + --> $DIR/repr-transparent-non-exhaustive.rs:1:9 + | +LL | #![deny(repr_transparent_external_private_fields)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #78586 + = note: this struct contains `Private`, which contains private fields, and makes it not a breaking change to become non-zero-sized in the future. + +error: zero-sized fields in repr(transparent) cannot contain external non-exhaustive types + --> $DIR/repr-transparent-non-exhaustive.rs:36:22 + | +LL | pub struct T6(Sized, NonExhaustive); + | ^^^^^^^^^^^^^ + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #78586 + = note: this struct contains `NonExhaustive`, which is marked with `#[non_exhaustive]`, and makes it not a breaking change to become non-zero-sized in the future. + +error: zero-sized fields in repr(transparent) cannot contain external non-exhaustive types + --> $DIR/repr-transparent-non-exhaustive.rs:41:22 + | +LL | pub struct T7(Sized, InternalIndirection); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #78586 + = note: this struct contains `Private`, which contains private fields, and makes it not a breaking change to become non-zero-sized in the future. + +error: zero-sized fields in repr(transparent) cannot contain external non-exhaustive types + --> $DIR/repr-transparent-non-exhaustive.rs:46:22 + | +LL | pub struct T8(Sized, InternalIndirection); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #78586 + = note: this struct contains `NonExhaustive`, which is marked with `#[non_exhaustive]`, and makes it not a breaking change to become non-zero-sized in the future. + +error: zero-sized fields in repr(transparent) cannot contain external non-exhaustive types + --> $DIR/repr-transparent-non-exhaustive.rs:51:22 + | +LL | pub struct T9(Sized, ExternalIndirection); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #78586 + = note: this struct contains `Private`, which contains private fields, and makes it not a breaking change to become non-zero-sized in the future. + +error: zero-sized fields in repr(transparent) cannot contain external non-exhaustive types + --> $DIR/repr-transparent-non-exhaustive.rs:56:23 + | +LL | pub struct T10(Sized, ExternalIndirection); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #78586 + = note: this struct contains `NonExhaustive`, which is marked with `#[non_exhaustive]`, and makes it not a breaking change to become non-zero-sized in the future. + +error: aborting due to 6 previous errors + From e65214785d85a4e2c76141e14eb38a55f1fd21d1 Mon Sep 17 00:00:00 2001 From: Deadbeef Date: Sun, 10 Jul 2022 13:31:58 +0000 Subject: [PATCH 27/29] add more tests --- .../repr-transparent-non-exhaustive.rs | 8 ++ .../repr/repr-transparent-non-exhaustive.rs | 46 ++++++++-- .../repr-transparent-non-exhaustive.stderr | 86 ++++++++++++++++--- 3 files changed, 122 insertions(+), 18 deletions(-) diff --git a/src/test/ui/repr/auxiliary/repr-transparent-non-exhaustive.rs b/src/test/ui/repr/auxiliary/repr-transparent-non-exhaustive.rs index b8ae5c2b729fd..4bf6b54fe0787 100644 --- a/src/test/ui/repr/auxiliary/repr-transparent-non-exhaustive.rs +++ b/src/test/ui/repr/auxiliary/repr-transparent-non-exhaustive.rs @@ -5,6 +5,14 @@ pub struct Private { _priv: () } #[non_exhaustive] pub struct NonExhaustive {} +#[non_exhaustive] +pub enum NonExhaustiveEnum {} + +pub enum NonExhaustiveVariant { + #[non_exhaustive] + A, +} + pub struct ExternalIndirection { pub x: T, } diff --git a/src/test/ui/repr/repr-transparent-non-exhaustive.rs b/src/test/ui/repr/repr-transparent-non-exhaustive.rs index 600caee8ba3a4..9ccd8610dad47 100644 --- a/src/test/ui/repr/repr-transparent-non-exhaustive.rs +++ b/src/test/ui/repr/repr-transparent-non-exhaustive.rs @@ -3,7 +3,13 @@ // aux-build: repr-transparent-non-exhaustive.rs extern crate repr_transparent_non_exhaustive; -use repr_transparent_non_exhaustive::{Private, NonExhaustive, ExternalIndirection}; +use repr_transparent_non_exhaustive::{ + Private, + NonExhaustive, + NonExhaustiveEnum, + NonExhaustiveVariant, + ExternalIndirection, +}; pub struct InternalPrivate { _priv: (), @@ -38,22 +44,52 @@ pub struct T6(Sized, NonExhaustive); //~| WARN this was previously accepted by the compiler #[repr(transparent)] -pub struct T7(Sized, InternalIndirection); +pub struct T7(Sized, NonExhaustiveEnum); //~^ ERROR zero-sized fields in repr(transparent) cannot contain external non-exhaustive types //~| WARN this was previously accepted by the compiler #[repr(transparent)] -pub struct T8(Sized, InternalIndirection); +pub struct T8(Sized, NonExhaustiveVariant); //~^ ERROR zero-sized fields in repr(transparent) cannot contain external non-exhaustive types //~| WARN this was previously accepted by the compiler #[repr(transparent)] -pub struct T9(Sized, ExternalIndirection); +pub struct T9(Sized, InternalIndirection); //~^ ERROR zero-sized fields in repr(transparent) cannot contain external non-exhaustive types //~| WARN this was previously accepted by the compiler #[repr(transparent)] -pub struct T10(Sized, ExternalIndirection); +pub struct T10(Sized, InternalIndirection); +//~^ ERROR zero-sized fields in repr(transparent) cannot contain external non-exhaustive types +//~| WARN this was previously accepted by the compiler + +#[repr(transparent)] +pub struct T11(Sized, InternalIndirection); +//~^ ERROR zero-sized fields in repr(transparent) cannot contain external non-exhaustive types +//~| WARN this was previously accepted by the compiler + +#[repr(transparent)] +pub struct T12(Sized, InternalIndirection); +//~^ ERROR zero-sized fields in repr(transparent) cannot contain external non-exhaustive types +//~| WARN this was previously accepted by the compiler + +#[repr(transparent)] +pub struct T13(Sized, ExternalIndirection); +//~^ ERROR zero-sized fields in repr(transparent) cannot contain external non-exhaustive types +//~| WARN this was previously accepted by the compiler + +#[repr(transparent)] +pub struct T14(Sized, ExternalIndirection); +//~^ ERROR zero-sized fields in repr(transparent) cannot contain external non-exhaustive types +//~| WARN this was previously accepted by the compiler + +#[repr(transparent)] +pub struct T15(Sized, ExternalIndirection); +//~^ ERROR zero-sized fields in repr(transparent) cannot contain external non-exhaustive types +//~| WARN this was previously accepted by the compiler + +#[repr(transparent)] +pub struct T16(Sized, ExternalIndirection); //~^ ERROR zero-sized fields in repr(transparent) cannot contain external non-exhaustive types //~| WARN this was previously accepted by the compiler diff --git a/src/test/ui/repr/repr-transparent-non-exhaustive.stderr b/src/test/ui/repr/repr-transparent-non-exhaustive.stderr index 3e45b2ab22cd5..3b1e334a0cbe2 100644 --- a/src/test/ui/repr/repr-transparent-non-exhaustive.stderr +++ b/src/test/ui/repr/repr-transparent-non-exhaustive.stderr @@ -1,5 +1,5 @@ error: zero-sized fields in repr(transparent) cannot contain external non-exhaustive types - --> $DIR/repr-transparent-non-exhaustive.rs:31:22 + --> $DIR/repr-transparent-non-exhaustive.rs:37:22 | LL | pub struct T5(Sized, Private); | ^^^^^^^ @@ -14,7 +14,7 @@ LL | #![deny(repr_transparent_external_private_fields)] = note: this struct contains `Private`, which contains private fields, and makes it not a breaking change to become non-zero-sized in the future. error: zero-sized fields in repr(transparent) cannot contain external non-exhaustive types - --> $DIR/repr-transparent-non-exhaustive.rs:36:22 + --> $DIR/repr-transparent-non-exhaustive.rs:42:22 | LL | pub struct T6(Sized, NonExhaustive); | ^^^^^^^^^^^^^ @@ -24,9 +24,29 @@ LL | pub struct T6(Sized, NonExhaustive); = note: this struct contains `NonExhaustive`, which is marked with `#[non_exhaustive]`, and makes it not a breaking change to become non-zero-sized in the future. error: zero-sized fields in repr(transparent) cannot contain external non-exhaustive types - --> $DIR/repr-transparent-non-exhaustive.rs:41:22 + --> $DIR/repr-transparent-non-exhaustive.rs:47:22 | -LL | pub struct T7(Sized, InternalIndirection); +LL | pub struct T7(Sized, NonExhaustiveEnum); + | ^^^^^^^^^^^^^^^^^ + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #78586 + = note: this enum contains `NonExhaustiveEnum`, which is marked with `#[non_exhaustive]`, and makes it not a breaking change to become non-zero-sized in the future. + +error: zero-sized fields in repr(transparent) cannot contain external non-exhaustive types + --> $DIR/repr-transparent-non-exhaustive.rs:52:22 + | +LL | pub struct T8(Sized, NonExhaustiveVariant); + | ^^^^^^^^^^^^^^^^^^^^ + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #78586 + = note: this enum contains `NonExhaustiveVariant`, which is marked with `#[non_exhaustive]`, and makes it not a breaking change to become non-zero-sized in the future. + +error: zero-sized fields in repr(transparent) cannot contain external non-exhaustive types + --> $DIR/repr-transparent-non-exhaustive.rs:57:22 + | +LL | pub struct T9(Sized, InternalIndirection); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! @@ -34,34 +54,74 @@ LL | pub struct T7(Sized, InternalIndirection); = note: this struct contains `Private`, which contains private fields, and makes it not a breaking change to become non-zero-sized in the future. error: zero-sized fields in repr(transparent) cannot contain external non-exhaustive types - --> $DIR/repr-transparent-non-exhaustive.rs:46:22 + --> $DIR/repr-transparent-non-exhaustive.rs:62:23 | -LL | pub struct T8(Sized, InternalIndirection); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | pub struct T10(Sized, InternalIndirection); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #78586 = note: this struct contains `NonExhaustive`, which is marked with `#[non_exhaustive]`, and makes it not a breaking change to become non-zero-sized in the future. error: zero-sized fields in repr(transparent) cannot contain external non-exhaustive types - --> $DIR/repr-transparent-non-exhaustive.rs:51:22 + --> $DIR/repr-transparent-non-exhaustive.rs:67:23 | -LL | pub struct T9(Sized, ExternalIndirection); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | pub struct T11(Sized, InternalIndirection); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #78586 + = note: this enum contains `NonExhaustiveEnum`, which is marked with `#[non_exhaustive]`, and makes it not a breaking change to become non-zero-sized in the future. + +error: zero-sized fields in repr(transparent) cannot contain external non-exhaustive types + --> $DIR/repr-transparent-non-exhaustive.rs:72:23 + | +LL | pub struct T12(Sized, InternalIndirection); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #78586 + = note: this enum contains `NonExhaustiveVariant`, which is marked with `#[non_exhaustive]`, and makes it not a breaking change to become non-zero-sized in the future. + +error: zero-sized fields in repr(transparent) cannot contain external non-exhaustive types + --> $DIR/repr-transparent-non-exhaustive.rs:77:23 + | +LL | pub struct T13(Sized, ExternalIndirection); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #78586 = note: this struct contains `Private`, which contains private fields, and makes it not a breaking change to become non-zero-sized in the future. error: zero-sized fields in repr(transparent) cannot contain external non-exhaustive types - --> $DIR/repr-transparent-non-exhaustive.rs:56:23 + --> $DIR/repr-transparent-non-exhaustive.rs:82:23 | -LL | pub struct T10(Sized, ExternalIndirection); +LL | pub struct T14(Sized, ExternalIndirection); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #78586 = note: this struct contains `NonExhaustive`, which is marked with `#[non_exhaustive]`, and makes it not a breaking change to become non-zero-sized in the future. -error: aborting due to 6 previous errors +error: zero-sized fields in repr(transparent) cannot contain external non-exhaustive types + --> $DIR/repr-transparent-non-exhaustive.rs:87:23 + | +LL | pub struct T15(Sized, ExternalIndirection); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #78586 + = note: this enum contains `NonExhaustiveEnum`, which is marked with `#[non_exhaustive]`, and makes it not a breaking change to become non-zero-sized in the future. + +error: zero-sized fields in repr(transparent) cannot contain external non-exhaustive types + --> $DIR/repr-transparent-non-exhaustive.rs:92:23 + | +LL | pub struct T16(Sized, ExternalIndirection); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #78586 + = note: this enum contains `NonExhaustiveVariant`, which is marked with `#[non_exhaustive]`, and makes it not a breaking change to become non-zero-sized in the future. + +error: aborting due to 12 previous errors From d812850d41beb038e8f4c0d51a8060308bc538c2 Mon Sep 17 00:00:00 2001 From: Deadbeef Date: Tue, 12 Jul 2022 10:33:52 +0000 Subject: [PATCH 28/29] fix documentation --- compiler/rustc_lint_defs/src/builtin.rs | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/compiler/rustc_lint_defs/src/builtin.rs b/compiler/rustc_lint_defs/src/builtin.rs index ae973e6a56382..49155f76800ce 100644 --- a/compiler/rustc_lint_defs/src/builtin.rs +++ b/compiler/rustc_lint_defs/src/builtin.rs @@ -3134,8 +3134,8 @@ declare_lint! { declare_lint! { /// The `repr_transparent_external_private_fields` lint - /// detects types marked #[repr(trasparent)] that (transitively) - /// contain an external ZST type marked #[non_exhaustive] + /// detects types marked `#[repr(trasparent)]` that (transitively) + /// contain an external ZST type marked `#[non_exhaustive]` /// /// ### Example /// @@ -3150,17 +3150,20 @@ declare_lint! { /// This will produce: /// /// ```text - /// error: deprecated `#[macro_use]` attribute used to import macros should be replaced at use sites with a `use` item to import the macro instead - /// --> src/main.rs:3:1 + /// error: zero-sized fields in repr(transparent) cannot contain external non-exhaustive types + /// --> src/main.rs:5:28 /// | - /// 3 | #[macro_use] - /// | ^^^^^^^^^^^^ + /// 5 | struct Bar(u32, ([u32; 0], NonExhaustiveZst)); + /// | ^^^^^^^^^^^^^^^^ /// | /// note: the lint level is defined here /// --> src/main.rs:1:9 /// | /// 1 | #![deny(repr_transparent_external_private_fields)] /// | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + /// = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + /// = note: for more information, see issue #78586 + /// = note: this struct contains `NonExhaustiveZst`, which is marked with `#[non_exhaustive]`, and makes it not a breaking change to become non-zero-sized in the future. /// ``` /// /// ### Explanation From 697dfb56c6f60540b24b442c1fbbacfa7945e8da Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lauren=C8=9Biu=20Nicola?= Date: Tue, 12 Jul 2022 14:18:31 +0300 Subject: [PATCH 29/29] :arrow_up: rust-analyzer --- src/tools/rust-analyzer | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tools/rust-analyzer b/src/tools/rust-analyzer index 75b22326dad19..5342f47f42766 160000 --- a/src/tools/rust-analyzer +++ b/src/tools/rust-analyzer @@ -1 +1 @@ -Subproject commit 75b22326dad1914c22484ab6672de5cae94f7457 +Subproject commit 5342f47f4276641ddb5f0a5e08fb307742d6cdc4