diff --git a/Cargo.lock b/Cargo.lock index 2bf07149cc86c..f8790be242afc 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3664,6 +3664,7 @@ dependencies = [ "rustc_arena", "rustc_ast", "rustc_attr", + "rustc_const_eval", "rustc_data_structures", "rustc_errors", "rustc_fs_util", diff --git a/compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs b/compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs index 6937e658ed5ee..9201bb035eadc 100644 --- a/compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs +++ b/compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs @@ -55,6 +55,7 @@ mod simd; pub(crate) use cpuid::codegen_cpuid_call; pub(crate) use llvm::codegen_llvm_intrinsic_call; +use rustc_const_eval::might_permit_raw_init::might_permit_raw_init; use rustc_middle::ty::print::with_no_trimmed_paths; use rustc_middle::ty::subst::SubstsRef; use rustc_span::symbol::{kw, sym, Symbol}; @@ -673,10 +674,7 @@ fn codegen_regular_intrinsic_call<'tcx>( } if intrinsic == sym::assert_zero_valid - && !layout.might_permit_raw_init( - fx, - InitKind::Zero, - fx.tcx.sess.opts.debugging_opts.strict_init_checks) { + && !might_permit_raw_init(fx.tcx, layout, InitKind::Zero) { with_no_trimmed_paths!({ crate::base::codegen_panic( @@ -689,10 +687,7 @@ fn codegen_regular_intrinsic_call<'tcx>( } if intrinsic == sym::assert_uninit_valid - && !layout.might_permit_raw_init( - fx, - InitKind::Uninit, - fx.tcx.sess.opts.debugging_opts.strict_init_checks) { + && !might_permit_raw_init(fx.tcx, layout, InitKind::Uninit) { with_no_trimmed_paths!({ crate::base::codegen_panic( diff --git a/compiler/rustc_codegen_cranelift/src/lib.rs b/compiler/rustc_codegen_cranelift/src/lib.rs index be2d3108c5fa9..23724538194a4 100644 --- a/compiler/rustc_codegen_cranelift/src/lib.rs +++ b/compiler/rustc_codegen_cranelift/src/lib.rs @@ -8,6 +8,7 @@ extern crate rustc_middle; extern crate rustc_ast; extern crate rustc_codegen_ssa; +extern crate rustc_const_eval; extern crate rustc_data_structures; extern crate rustc_errors; extern crate rustc_fs_util; diff --git a/compiler/rustc_codegen_ssa/Cargo.toml b/compiler/rustc_codegen_ssa/Cargo.toml index faabea92f5a6c..81c8b9ceb136e 100644 --- a/compiler/rustc_codegen_ssa/Cargo.toml +++ b/compiler/rustc_codegen_ssa/Cargo.toml @@ -40,6 +40,7 @@ rustc_metadata = { path = "../rustc_metadata" } rustc_query_system = { path = "../rustc_query_system" } rustc_target = { path = "../rustc_target" } rustc_session = { path = "../rustc_session" } +rustc_const_eval = { path = "../rustc_const_eval" } [dependencies.object] version = "0.29.0" diff --git a/compiler/rustc_codegen_ssa/src/mir/block.rs b/compiler/rustc_codegen_ssa/src/mir/block.rs index b8e3cb32ef633..a0a9065180a65 100644 --- a/compiler/rustc_codegen_ssa/src/mir/block.rs +++ b/compiler/rustc_codegen_ssa/src/mir/block.rs @@ -528,7 +528,6 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { source_info: mir::SourceInfo, target: Option<mir::BasicBlock>, cleanup: Option<mir::BasicBlock>, - strict_validity: bool, ) -> bool { // Emit a panic or a no-op for `assert_*` intrinsics. // These are intrinsics that compile to panics so that we can get a message @@ -546,13 +545,15 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { _ => None, }); if let Some(intrinsic) = panic_intrinsic { + use rustc_const_eval::might_permit_raw_init::might_permit_raw_init; use AssertIntrinsic::*; + let ty = instance.unwrap().substs.type_at(0); let layout = bx.layout_of(ty); let do_panic = match intrinsic { Inhabited => layout.abi.is_uninhabited(), - ZeroValid => !layout.might_permit_raw_init(bx, InitKind::Zero, strict_validity), - UninitValid => !layout.might_permit_raw_init(bx, InitKind::Uninit, strict_validity), + ZeroValid => !might_permit_raw_init(bx.tcx(), layout, InitKind::Zero), + UninitValid => !might_permit_raw_init(bx.tcx(), layout, InitKind::Uninit), }; if do_panic { let msg_str = with_no_visible_paths!({ @@ -687,7 +688,6 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { source_info, target, cleanup, - self.cx.tcx().sess.opts.debugging_opts.strict_init_checks, ) { return; } diff --git a/compiler/rustc_const_eval/src/const_eval/machine.rs b/compiler/rustc_const_eval/src/const_eval/machine.rs index 29ab1d187719c..e00e667fb71e2 100644 --- a/compiler/rustc_const_eval/src/const_eval/machine.rs +++ b/compiler/rustc_const_eval/src/const_eval/machine.rs @@ -104,7 +104,7 @@ pub struct CompileTimeInterpreter<'mir, 'tcx> { } impl<'mir, 'tcx> CompileTimeInterpreter<'mir, 'tcx> { - pub(super) fn new(const_eval_limit: Limit, can_access_statics: bool) -> Self { + pub(crate) fn new(const_eval_limit: Limit, can_access_statics: bool) -> Self { CompileTimeInterpreter { steps_remaining: const_eval_limit.0, stack: Vec::new(), diff --git a/compiler/rustc_const_eval/src/interpret/intrinsics.rs b/compiler/rustc_const_eval/src/interpret/intrinsics.rs index 93b64d9d37a49..0503c93beccf5 100644 --- a/compiler/rustc_const_eval/src/interpret/intrinsics.rs +++ b/compiler/rustc_const_eval/src/interpret/intrinsics.rs @@ -22,6 +22,8 @@ use super::{ Pointer, }; +use crate::might_permit_raw_init::might_permit_raw_init; + mod caller_location; mod type_name; @@ -413,35 +415,33 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { ), )?; } - if intrinsic_name == sym::assert_zero_valid - && !layout.might_permit_raw_init( - self, - InitKind::Zero, - self.tcx.sess.opts.debugging_opts.strict_init_checks, - ) - { - M::abort( - self, - format!( - "aborted execution: attempted to zero-initialize type `{}`, which is invalid", - ty - ), - )?; + + if intrinsic_name == sym::assert_zero_valid { + let should_panic = !might_permit_raw_init(*self.tcx, layout, InitKind::Zero); + + if should_panic { + M::abort( + self, + format!( + "aborted execution: attempted to zero-initialize type `{}`, which is invalid", + ty + ), + )?; + } } - if intrinsic_name == sym::assert_uninit_valid - && !layout.might_permit_raw_init( - self, - InitKind::Uninit, - self.tcx.sess.opts.debugging_opts.strict_init_checks, - ) - { - M::abort( - self, - format!( - "aborted execution: attempted to leave type `{}` uninitialized, which is invalid", - ty - ), - )?; + + if intrinsic_name == sym::assert_uninit_valid { + let should_panic = !might_permit_raw_init(*self.tcx, layout, InitKind::Uninit); + + if should_panic { + M::abort( + self, + format!( + "aborted execution: attempted to leave type `{}` uninitialized, which is invalid", + ty + ), + )?; + } } } sym::simd_insert => { diff --git a/compiler/rustc_const_eval/src/lib.rs b/compiler/rustc_const_eval/src/lib.rs index d65d4f7eb720e..70bfd109c437d 100644 --- a/compiler/rustc_const_eval/src/lib.rs +++ b/compiler/rustc_const_eval/src/lib.rs @@ -33,6 +33,7 @@ extern crate rustc_middle; pub mod const_eval; mod errors; pub mod interpret; +pub mod might_permit_raw_init; pub mod transform; pub mod util; diff --git a/compiler/rustc_const_eval/src/might_permit_raw_init.rs b/compiler/rustc_const_eval/src/might_permit_raw_init.rs new file mode 100644 index 0000000000000..7a3741c541a1f --- /dev/null +++ b/compiler/rustc_const_eval/src/might_permit_raw_init.rs @@ -0,0 +1,44 @@ +use crate::const_eval::CompileTimeInterpreter; +use crate::interpret::{InterpCx, MemoryKind, OpTy}; +use rustc_middle::ty::layout::LayoutCx; +use rustc_middle::ty::{layout::TyAndLayout, ParamEnv, TyCtxt}; +use rustc_session::Limit; +use rustc_target::abi::InitKind; + +pub fn might_permit_raw_init<'tcx>( + tcx: TyCtxt<'tcx>, + ty: TyAndLayout<'tcx>, + kind: InitKind, +) -> bool { + let strict = tcx.sess.opts.debugging_opts.strict_init_checks; + + if strict { + let machine = CompileTimeInterpreter::new(Limit::new(0), false); + + let mut cx = InterpCx::new(tcx, rustc_span::DUMMY_SP, ParamEnv::reveal_all(), machine); + + // We could panic here... Or we could just return "yeah it's valid whatever". Or let + // codegen_panic_intrinsic return an error that halts compilation. + // I'm not exactly sure *when* this can fail. OOM? + let allocated = cx + .allocate(ty, MemoryKind::Machine(crate::const_eval::MemoryKind::Heap)) + .expect("failed to allocate for uninit check"); + + if kind == InitKind::Zero { + // Again, unclear what to do here if it fails. + cx.write_bytes_ptr( + allocated.ptr, + std::iter::repeat(0_u8).take(ty.layout.size().bytes_usize()), + ) + .expect("failed to write bytes for zero valid check"); + } + + let ot: OpTy<'_, _> = allocated.into(); + + // Assume that if it failed, it's a validation failure. + cx.validate_operand(&ot).is_ok() + } else { + let layout_cx = LayoutCx { tcx, param_env: ParamEnv::reveal_all() }; + ty.might_permit_raw_init(&layout_cx, kind) + } +} 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..2ddaf9201098e 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 `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_lint_defs/src/builtin.rs b/compiler/rustc_lint_defs/src/builtin.rs index 9fc2249b29019..49155f76800ce 100644 --- a/compiler/rustc_lint_defs/src/builtin.rs +++ b/compiler/rustc_lint_defs/src/builtin.rs @@ -3132,6 +3132,59 @@ 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: zero-sized fields in repr(transparent) cannot contain external non-exhaustive types + /// --> src/main.rs:5:28 + /// | + /// 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 <https://github.com/rust-lang/rust/issues/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 + /// + /// 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 <https://github.com/rust-lang/rust/issues/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 +3290,7 @@ declare_lint_pass! { DEPRECATED_WHERE_CLAUSE_LOCATION, TEST_UNSTABLE_LINT, FFI_UNWIND_CALLS, + REPR_TRANSPARENT_EXTERNAL_PRIVATE_FIELDS, ] } 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/compiler/rustc_passes/src/stability.rs b/compiler/rustc_passes/src/stability.rs index 12050dceb60a6..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,39 +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!() }; - - // 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 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<T>` are unstable", - ) - .emit(); - } - } - } - } - _ => (/* pass */), } intravisit::walk_item(self, item); diff --git a/compiler/rustc_target/src/abi/mod.rs b/compiler/rustc_target/src/abi/mod.rs index d1eafd6ac5fb8..2c3340ba4448b 100644 --- a/compiler/rustc_target/src/abi/mod.rs +++ b/compiler/rustc_target/src/abi/mod.rs @@ -1372,7 +1372,7 @@ pub struct PointeeInfo { /// Used in `might_permit_raw_init` to indicate the kind of initialisation /// that is checked to be valid -#[derive(Copy, Clone, Debug)] +#[derive(Copy, Clone, Debug, PartialEq, Eq)] pub enum InitKind { Zero, Uninit, @@ -1487,14 +1487,18 @@ impl<'a, Ty> TyAndLayout<'a, Ty> { /// /// `init_kind` indicates if the memory is zero-initialized or left uninitialized. /// - /// `strict` is an opt-in debugging flag added in #97323 that enables more checks. + /// This code is intentionally conservative, and will not detect + /// * zero init of an enum whose 0 variant does not allow zero initialization + /// * making uninitialized types who have a full valid range (ints, floats, raw pointers) + /// * Any form of invalid value being made inside an array (unless the value is uninhabited) /// - /// This is conservative: in doubt, it will answer `true`. + /// A strict form of these checks that uses const evaluation exists in + /// [`rustc_const_eval::might_permit_raw_init`], and a tracking issue for making these checks + /// stricter is <https://github.com/rust-lang/rust/issues/66151>. /// - /// FIXME: Once we removed all the conservatism, we could alternatively - /// create an all-0/all-undef constant and run the const value validator to see if - /// this is a valid value for the given type. - pub fn might_permit_raw_init<C>(self, cx: &C, init_kind: InitKind, strict: bool) -> bool + /// FIXME: Once all the conservatism is removed from here, and the checks are ran by default, + /// we can use the const evaluation checks always instead. + pub fn might_permit_raw_init<C>(self, cx: &C, init_kind: InitKind) -> bool where Self: Copy, Ty: TyAbiInterface<'a, C>, @@ -1507,13 +1511,8 @@ impl<'a, Ty> TyAndLayout<'a, Ty> { s.valid_range(cx).contains(0) } InitKind::Uninit => { - if strict { - // The type must be allowed to be uninit (which means "is a union"). - s.is_uninit_valid() - } else { - // The range must include all values. - s.is_always_valid(cx) - } + // The range must include all values. + s.is_always_valid(cx) } } }; @@ -1534,19 +1533,12 @@ impl<'a, Ty> TyAndLayout<'a, Ty> { // If we have not found an error yet, we need to recursively descend into fields. match &self.fields { FieldsShape::Primitive | FieldsShape::Union { .. } => {} - FieldsShape::Array { count, .. } => { + FieldsShape::Array { .. } => { // FIXME(#66151): For now, we are conservative and do not check arrays by default. - if strict - && *count > 0 - && !self.field(cx, 0).might_permit_raw_init(cx, init_kind, strict) - { - // Found non empty array with a type that is unhappy about this kind of initialization - return false; - } } FieldsShape::Arbitrary { offsets, .. } => { for idx in 0..offsets.len() { - if !self.field(cx, idx).might_permit_raw_init(cx, init_kind, strict) { + if !self.field(cx, idx).might_permit_raw_init(cx, init_kind) { // We found a field that is unhappy with this kind of initialization. return false; } diff --git a/compiler/rustc_typeck/src/check/check.rs b/compiler/rustc_typeck/src/check/check.rs index e9709b64d930e..dfcd35d2178e7 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; @@ -401,11 +402,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().is_some_and(|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 +459,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 { @@ -1318,7 +1348,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 +1358,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 +1419,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/compiler/rustc_typeck/src/lib.rs b/compiler/rustc_typeck/src/lib.rs index dd712fd7ed71d..f98ae46c58730 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/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<T: Iterator<Item: Copy, Item: Send>> { //~^ ERROR the value of the associated type `Item` (from trait `Iterator`) is already specified [E0719] @@ -74,36 +74,36 @@ where union UI1<T: Iterator<Item: Copy, Item: Send>> { //~^ ERROR the value of the associated type `Item` (from trait `Iterator`) is already specified [E0719] - f: T, + f: ManuallyDrop<T>, } union UI2<T: Iterator<Item: Copy, Item: Copy>> { //~^ ERROR the value of the associated type `Item` (from trait `Iterator`) is already specified [E0719] - f: T, + f: ManuallyDrop<T>, } union UI3<T: Iterator<Item: 'static, Item: 'static>> { //~^ ERROR the value of the associated type `Item` (from trait `Iterator`) is already specified [E0719] - f: T, + f: ManuallyDrop<T>, } union UW1<T> where T: Iterator<Item: Copy, Item: Send>, //~^ ERROR the value of the associated type `Item` (from trait `Iterator`) is already specified [E0719] { - f: T, + f: ManuallyDrop<T>, } union UW2<T> where T: Iterator<Item: Copy, Item: Copy>, //~^ ERROR the value of the associated type `Item` (from trait `Iterator`) is already specified [E0719] { - f: T, + f: ManuallyDrop<T>, } union UW3<T> where T: Iterator<Item: 'static, Item: 'static>, //~^ ERROR the value of the associated type `Item` (from trait `Iterator`) is already specified [E0719] { - f: T, + f: ManuallyDrop<T>, } fn FI1<T: Iterator<Item: Copy, Item: Send>>() {} 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<Item: Copy> } //~^ ERROR associated type bounds are not allowed within structs, enums, or unions @@ -17,12 +18,12 @@ enum E3 { V(dyn Iterator<Item: 'static>) } //~^ ERROR associated type bounds are not allowed within structs, enums, or unions //~| ERROR the size for values of type `(dyn Iterator<Item = impl Sized> + 'static)` -union U1 { f: dyn Iterator<Item: Copy> } +union U1 { f: ManuallyDrop<dyn Iterator<Item: Copy>> } //~^ ERROR associated type bounds are not allowed within structs, enums, or unions //~| ERROR the size for values of type `(dyn Iterator<Item = impl Copy> + 'static)` -union U2 { f: Box<dyn Iterator<Item: Copy>> } +union U2 { f: ManuallyDrop<Box<dyn Iterator<Item: Copy>>> } //~^ ERROR associated type bounds are not allowed within structs, enums, or unions -union U3 { f: dyn Iterator<Item: 'static> } +union U3 { f: ManuallyDrop<dyn Iterator<Item: 'static>> } //~^ ERROR associated type bounds are not allowed within structs, enums, or unions //~| ERROR the size for values of type `(dyn Iterator<Item = impl Sized> + '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<Item: Copy> } | ^^^^^^^^^^ 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<dyn Iterator<Item: Copy>> } | ^^^^^^^^^^ 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<Item: 'static> } | ^^^^^^^^^^^^^ 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<Item: Copy>) } | ^^^^^^^^^^ 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<dyn Iterator<Item: Copy>>) } | ^^^^^^^^^^ 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<Item: 'static>) } | ^^^^^^^^^^^^^ 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<Item: Copy> } - | ^^^^^^^^^^ +LL | union U1 { f: ManuallyDrop<dyn Iterator<Item: Copy>> } + | ^^^^^^^^^^ 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<dyn Iterator<Item: Copy>> } - | ^^^^^^^^^^ +LL | union U2 { f: ManuallyDrop<Box<dyn Iterator<Item: Copy>>> } + | ^^^^^^^^^^ 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<Item: 'static> } - | ^^^^^^^^^^^^^ +LL | union U3 { f: ManuallyDrop<dyn Iterator<Item: 'static>> } + | ^^^^^^^^^^^^^ error[E0277]: the size for values of type `(dyn Iterator<Item = impl Copy> + '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<Item: Copy>) } | ^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time @@ -71,7 +71,7 @@ LL | enum E1 { V(Box<dyn Iterator<Item: Copy>>) } | ++++ + error[E0277]: the size for values of type `(dyn Iterator<Item = impl Sized> + '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<Item: 'static>) } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time @@ -89,40 +89,42 @@ LL | enum E3 { V(Box<dyn Iterator<Item: 'static>>) } | ++++ + error[E0277]: the size for values of type `(dyn Iterator<Item = impl Copy> + '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<Item: Copy> } - | ^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time +LL | union U1 { f: ManuallyDrop<dyn Iterator<Item: Copy>> } + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time | - = help: the trait `Sized` is not implemented for `(dyn Iterator<Item = impl Copy> + 'static)` + = help: within `ManuallyDrop<(dyn Iterator<Item = impl Copy> + 'static)>`, the trait `Sized` is not implemented for `(dyn Iterator<Item = impl Copy> + 'static)` + = note: required because it appears within the type `ManuallyDrop<(dyn Iterator<Item = impl Copy> + '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<Item: Copy> } +LL | union U1 { f: &ManuallyDrop<dyn Iterator<Item: Copy>> } | + help: the `Box` type always has a statically known size and allocates its contents in the heap | -LL | union U1 { f: Box<dyn Iterator<Item: Copy>> } - | ++++ + +LL | union U1 { f: Box<ManuallyDrop<dyn Iterator<Item: Copy>>> } + | ++++ + error[E0277]: the size for values of type `(dyn Iterator<Item = impl Sized> + '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<Item: 'static> } - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time +LL | union U3 { f: ManuallyDrop<dyn Iterator<Item: 'static>> } + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time | - = help: the trait `Sized` is not implemented for `(dyn Iterator<Item = impl Sized> + 'static)` + = help: within `ManuallyDrop<(dyn Iterator<Item = impl Sized> + 'static)>`, the trait `Sized` is not implemented for `(dyn Iterator<Item = impl Sized> + 'static)` + = note: required because it appears within the type `ManuallyDrop<(dyn Iterator<Item = impl Sized> + '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<Item: 'static> } +LL | union U3 { f: &ManuallyDrop<dyn Iterator<Item: 'static>> } | + help: the `Box` type always has a statically known size and allocates its contents in the heap | -LL | union U3 { f: Box<dyn Iterator<Item: 'static>> } - | ++++ + +LL | union U3 { f: Box<ManuallyDrop<dyn Iterator<Item: 'static>>> } + | ++++ + 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<A>, + b: ManuallyDrop<B>, } 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<NonCopy>, + n2: ManuallyDrop<NonCopy>, } union Ucc { c1: Copy, @@ -14,24 +14,24 @@ union Ucc { } union Ucn { c: Copy, - n: NonCopy, + n: ManuallyDrop<NonCopy>, } 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.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 .<deref>.y.<enum-variant(B)>.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.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 .<deref>.y.<enum-variant(B)>.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<u32>, + cell: ManuallyDrop<Cell<u32>>, } 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<u32> } +union U { i: u32, c: ManuallyDrop<Cell<u32>> } -const C1: Cell<u32> = { - unsafe { U { c: Cell::new(0) }.c } +const C1: ManuallyDrop<Cell<u32>> = { + unsafe { U { c: ManuallyDrop::new(Cell::new(0)) }.c } }; -const C2: Cell<u32> = { +const C2: ManuallyDrop<Cell<u32>> = { unsafe { U { i : 0 }.c } }; -const C3: Cell<u32> = { +const C3: ManuallyDrop<Cell<u32>> = { 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<T: Tr1<As1: Tr2>> { union _Un1<T: Tr1<As1: Tr2>> { //~^ ERROR associated type bounds are unstable - outest: std::mem::ManuallyDrop<T>, - outer: T::As1, - inner: <T::As1 as Tr2>::As2, + outest: ManuallyDrop<T>, + outer: ManuallyDrop<T::As1>, + inner: ManuallyDrop<<T::As1 as Tr2>::As2>, } type _TaWhere1<T> where T: Iterator<Item: Copy> = T; diff --git a/src/test/ui/feature-gates/feature-gate-untagged_unions.rs b/src/test/ui/feature-gates/feature-gate-untagged_unions.rs deleted file mode 100644 index af8d8e92b20bd..0000000000000 --- a/src/test/ui/feature-gates/feature-gate-untagged_unions.rs +++ /dev/null @@ -1,35 +0,0 @@ -// ignore-tidy-linelength - -union U1 { // OK - a: u8, -} - -union U2<T: Copy> { // OK - a: T, -} - -union U22<T> { // OK - a: std::mem::ManuallyDrop<T>, -} - -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<i32>, //~ ERROR unions with non-`Copy` fields other than `ManuallyDrop<T>` are unstable -} - -union U4<T> { - a: T, //~ ERROR unions cannot contain fields that may need dropping -} - -union U5 { // Having a drop impl is OK - a: u8, -} - -impl Drop for U5 { - fn drop(&mut self) {} -} - -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 deleted file mode 100644 index 9e4a89f80c852..0000000000000 --- a/src/test/ui/feature-gates/feature-gate-untagged_unions.stderr +++ /dev/null @@ -1,37 +0,0 @@ -error[E0658]: unions with non-`Copy` fields other than `ManuallyDrop<T>` are unstable - --> $DIR/feature-gate-untagged_unions.rs:20:5 - | -LL | a: std::cell::RefCell<i32>, - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = note: see issue #55149 <https://github.com/rust-lang/rust/issues/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:16:5 - | -LL | a: String, - | ^^^^^^^^^ - | - = 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<String>, - | +++++++++++++++++++++++ + - -error[E0740]: unions cannot contain fields that may need dropping - --> $DIR/feature-gate-untagged_unions.rs:24:5 - | -LL | a: T, - | ^^^^ - | - = 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<T>, - | +++++++++++++++++++++++ + - -error: aborting due to 3 previous errors - -Some errors have detailed explanations: E0658, E0740. -For more information about an error, try `rustc --explain E0658`. diff --git a/src/test/ui/intrinsics/panic-uninitialized-zeroed.rs b/src/test/ui/intrinsics/panic-uninitialized-zeroed.rs index 3ffd35ecdb8da..255151a96032c 100644 --- a/src/test/ui/intrinsics/panic-uninitialized-zeroed.rs +++ b/src/test/ui/intrinsics/panic-uninitialized-zeroed.rs @@ -57,6 +57,13 @@ enum LR_NonZero { struct ZeroSized; +#[allow(dead_code)] +#[repr(i32)] +enum ZeroIsValid { + Zero(u8) = 0, + One(NonNull<()>) = 1, +} + fn test_panic_msg<T>(op: impl (FnOnce() -> T) + panic::UnwindSafe, msg: &str) { let err = panic::catch_unwind(op).err(); assert_eq!( @@ -152,33 +159,12 @@ fn main() { "attempted to zero-initialize type `*const dyn core::marker::Send`, which is invalid" ); - /* FIXME(#66151) we conservatively do not error here yet. - test_panic_msg( - || mem::uninitialized::<LR_NonZero>(), - "attempted to leave type `LR_NonZero` uninitialized, which is invalid" - ); - test_panic_msg( - || mem::zeroed::<LR_NonZero>(), - "attempted to zero-initialize type `LR_NonZero`, which is invalid" - ); - - test_panic_msg( - || mem::uninitialized::<ManuallyDrop<LR_NonZero>>(), - "attempted to leave type `std::mem::ManuallyDrop<LR_NonZero>` uninitialized, \ - which is invalid" - ); - test_panic_msg( - || mem::zeroed::<ManuallyDrop<LR_NonZero>>(), - "attempted to zero-initialize type `std::mem::ManuallyDrop<LR_NonZero>`, \ - which is invalid" - ); - */ - test_panic_msg( || mem::uninitialized::<(NonNull<u32>, u32, u32)>(), "attempted to leave type `(core::ptr::non_null::NonNull<u32>, u32, u32)` uninitialized, \ which is invalid" ); + test_panic_msg( || mem::zeroed::<(NonNull<u32>, u32, u32)>(), "attempted to zero-initialize type `(core::ptr::non_null::NonNull<u32>, u32, u32)`, \ @@ -196,11 +182,23 @@ fn main() { which is invalid" ); + test_panic_msg( + || mem::uninitialized::<LR_NonZero>(), + "attempted to leave type `LR_NonZero` uninitialized, which is invalid" + ); + + test_panic_msg( + || mem::uninitialized::<ManuallyDrop<LR_NonZero>>(), + "attempted to leave type `core::mem::manually_drop::ManuallyDrop<LR_NonZero>` uninitialized, \ + which is invalid" + ); + test_panic_msg( || mem::uninitialized::<NoNullVariant>(), "attempted to leave type `NoNullVariant` uninitialized, \ which is invalid" ); + test_panic_msg( || mem::zeroed::<NoNullVariant>(), "attempted to zero-initialize type `NoNullVariant`, \ @@ -212,10 +210,12 @@ fn main() { || mem::uninitialized::<bool>(), "attempted to leave type `bool` uninitialized, which is invalid" ); + test_panic_msg( || mem::uninitialized::<LR>(), "attempted to leave type `LR` uninitialized, which is invalid" ); + test_panic_msg( || mem::uninitialized::<ManuallyDrop<LR>>(), "attempted to leave type `core::mem::manually_drop::ManuallyDrop<LR>` uninitialized, which is invalid" @@ -229,6 +229,7 @@ fn main() { let _val = mem::zeroed::<Option<&'static i32>>(); let _val = mem::zeroed::<MaybeUninit<NonNull<u32>>>(); let _val = mem::zeroed::<[!; 0]>(); + let _val = mem::zeroed::<ZeroIsValid>(); let _val = mem::uninitialized::<MaybeUninit<bool>>(); let _val = mem::uninitialized::<[!; 0]>(); let _val = mem::uninitialized::<()>(); @@ -259,12 +260,33 @@ fn main() { || mem::zeroed::<[NonNull<()>; 1]>(), "attempted to zero-initialize type `[core::ptr::non_null::NonNull<()>; 1]`, which is invalid" ); + + // FIXME(#66151) we conservatively do not error here yet (by default). + test_panic_msg( + || mem::zeroed::<LR_NonZero>(), + "attempted to zero-initialize type `LR_NonZero`, which is invalid" + ); + + test_panic_msg( + || mem::zeroed::<ManuallyDrop<LR_NonZero>>(), + "attempted to zero-initialize type `core::mem::manually_drop::ManuallyDrop<LR_NonZero>`, \ + which is invalid" + ); } else { // These are UB because they have not been officially blessed, but we await the resolution // of <https://github.com/rust-lang/unsafe-code-guidelines/issues/71> before doing // anything about that. let _val = mem::uninitialized::<i32>(); let _val = mem::uninitialized::<*const ()>(); + + // These are UB, but best to test them to ensure we don't become unintentionally + // stricter. + + // It's currently unchecked to create invalid enums and values inside arrays. + let _val = mem::zeroed::<LR_NonZero>(); + let _val = mem::zeroed::<[LR_NonZero; 1]>(); + let _val = mem::zeroed::<[NonNull<()>; 1]>(); + let _val = mem::uninitialized::<[NonNull<()>; 1]>(); } } } 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<A>, + b: ManuallyDrop<B>, } 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/auxiliary/repr-transparent-non-exhaustive.rs b/src/test/ui/repr/auxiliary/repr-transparent-non-exhaustive.rs new file mode 100644 index 0000000000000..4bf6b54fe0787 --- /dev/null +++ b/src/test/ui/repr/auxiliary/repr-transparent-non-exhaustive.rs @@ -0,0 +1,18 @@ +#![crate_type = "lib"] + +pub struct Private { _priv: () } + +#[non_exhaustive] +pub struct NonExhaustive {} + +#[non_exhaustive] +pub enum NonExhaustiveEnum {} + +pub enum NonExhaustiveVariant { + #[non_exhaustive] + A, +} + +pub struct ExternalIndirection<T> { + pub x: T, +} 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/repr/repr-transparent-non-exhaustive.rs b/src/test/ui/repr/repr-transparent-non-exhaustive.rs new file mode 100644 index 0000000000000..9ccd8610dad47 --- /dev/null +++ b/src/test/ui/repr/repr-transparent-non-exhaustive.rs @@ -0,0 +1,96 @@ +#![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, + NonExhaustiveEnum, + NonExhaustiveVariant, + ExternalIndirection, +}; + +pub struct InternalPrivate { + _priv: (), +} + +#[non_exhaustive] +pub struct InternalNonExhaustive; + +pub struct InternalIndirection<T> { + 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, 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, 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, InternalIndirection<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 T10(Sized, InternalIndirection<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 T11(Sized, InternalIndirection<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 T12(Sized, InternalIndirection<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 T13(Sized, ExternalIndirection<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 T14(Sized, ExternalIndirection<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 T15(Sized, ExternalIndirection<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 T16(Sized, ExternalIndirection<NonExhaustiveVariant>); +//~^ 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..3b1e334a0cbe2 --- /dev/null +++ b/src/test/ui/repr/repr-transparent-non-exhaustive.stderr @@ -0,0 +1,127 @@ +error: zero-sized fields in repr(transparent) cannot contain external non-exhaustive types + --> $DIR/repr-transparent-non-exhaustive.rs:37: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 <https://github.com/rust-lang/rust/issues/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:42: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 <https://github.com/rust-lang/rust/issues/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:47:22 + | +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 <https://github.com/rust-lang/rust/issues/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 <https://github.com/rust-lang/rust/issues/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<Private>); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = 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 <https://github.com/rust-lang/rust/issues/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:62:23 + | +LL | pub struct T10(Sized, InternalIndirection<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 <https://github.com/rust-lang/rust/issues/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:67:23 + | +LL | pub struct T11(Sized, InternalIndirection<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 <https://github.com/rust-lang/rust/issues/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<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 <https://github.com/rust-lang/rust/issues/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<Private>); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = 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 <https://github.com/rust-lang/rust/issues/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:82:23 + | +LL | pub struct T14(Sized, ExternalIndirection<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 <https://github.com/rust-lang/rust/issues/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:87:23 + | +LL | pub struct T15(Sized, ExternalIndirection<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 <https://github.com/rust-lang/rust/issues/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<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 <https://github.com/rust-lang/rust/issues/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 + 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/union/field_checks.rs b/src/test/ui/union/field_checks.rs new file mode 100644 index 0000000000000..d5d1e44ac855c --- /dev/null +++ b/src/test/ui/union/field_checks.rs @@ -0,0 +1,65 @@ +use std::mem::ManuallyDrop; + +union U1 { // OK + a: u8, +} + +union U2<T: Copy> { // OK + a: T, +} + +union U22<T> { // OK + a: ManuallyDrop<T>, +} + +union U23<T> { // OK + a: (ManuallyDrop<T>, i32), +} + +union U24<T> { // OK + a: [ManuallyDrop<T>; 2], +} + +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 + a: std::cell::RefCell<i32>, //~ ERROR unions cannot contain fields that may need dropping +} + +union U4<T> { + a: T, //~ ERROR unions cannot contain fields that may need dropping +} + +union U5 { // Having a drop impl is OK + a: u8, +} + +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 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, +} + +union U7<T> { // OK + f: (&'static mut i32, ManuallyDrop<T>, i32), +} + +union U8<T> { // OK + f1: [(&'static mut i32, i32); 8], + f2: [ManuallyDrop<T>; 2], +} + +fn main() {} diff --git a/src/test/ui/union/field_checks.stderr b/src/test/ui/union/field_checks.stderr new file mode 100644 index 0000000000000..1f97e97ac6ede --- /dev/null +++ b/src/test/ui/union/field_checks.stderr @@ -0,0 +1,63 @@ +error[E0740]: unions cannot contain fields that may need dropping + --> $DIR/field_checks.rs:24:5 + | +LL | a: String, + | ^^^^^^^^^ + | + = 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<String>, + | +++++++++++++++++++++++ + + +error[E0740]: unions cannot contain fields that may need dropping + --> $DIR/field_checks.rs:28:5 + | +LL | a: std::cell::RefCell<i32>, + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = 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<std::cell::RefCell<i32>>, + | +++++++++++++++++++++++ + + +error[E0740]: unions cannot contain fields that may need dropping + --> $DIR/field_checks.rs:32:5 + | +LL | a: T, + | ^^^^ + | + = 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<T>, + | +++++++++++++++++++++++ + + +error[E0740]: unions cannot contain fields that may need dropping + --> $DIR/field_checks.rs:44: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<U5>, + | +++++++++++++++++++++++ + + +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/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<u8>, MockVec<u8>), MockVec<u8>)>` + --> $DIR/union-borrow-move-parent-sibling.rs:62:13 + | +LL | let a = u.x.0; + | ^^^^^ + | | + | move occurs because value has type `(MockVec<u8>, MockVec<u8>)`, 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<u8>, MockVec<u8>), MockVec<u8>)>` --> $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<u8>`, 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<T> { @@ -44,47 +44,49 @@ impl<T> DerefMut for MockVec<T> { union U { - x: ((MockVec<u8>, MockVec<u8>), MockVec<u8>), - y: MockBox<MockVec<u8>>, + x: ManuallyDrop<((MockVec<u8>, MockVec<u8>), MockVec<u8>)>, + y: ManuallyDrop<MockBox<MockVec<u8>>>, } fn use_borrow<T>(_: &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<u8>, MockVec<u8>), MockVec<u8>)>` + --> $DIR/union-borrow-move-parent-sibling.rs:62:13 + | +LL | let a = u.x.0; + | ^^^^^ + | | + | move occurs because value has type `(MockVec<u8>, MockVec<u8>)`, 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<u8>, MockVec<u8>), MockVec<u8>)>` --> $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<u8>`, 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<Bar>, - | +++++++++++++++++++++++ + - -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<i32>`, which does not implement the `Copy` trait + | move occurs because `x.f1_nocopy` has type `ManuallyDrop<RefCell<i32>>`, 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<T>(x: T) {} union U1 { - f1_nocopy: RefCell<i32>, - f2_nocopy: RefCell<i32>, + f1_nocopy: ManuallyDrop<RefCell<i32>>, + f2_nocopy: ManuallyDrop<RefCell<i32>>, f3_copy: i32, } union U2 { - f1_nocopy: RefCell<i32>, + f1_nocopy: ManuallyDrop<RefCell<i32>>, } 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<i32>`, which does not implement the `Copy` trait + | move occurs because `x.f1_nocopy` has type `ManuallyDrop<RefCell<i32>>`, 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..4bdf7c6872fa5 100644 --- a/src/test/ui/union/union-nonrepresentable.rs +++ b/src/test/ui/union/union-nonrepresentable.rs @@ -1,8 +1,6 @@ -#![feature(untagged_unions)] - union U { //~ ERROR recursive type `U` has infinite size a: u8, - b: U, + b: std::mem::ManuallyDrop<U>, } fn main() {} diff --git a/src/test/ui/union/union-nonrepresentable.stderr b/src/test/ui/union/union-nonrepresentable.stderr index 7da7c870e704b..9804b1418b208 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:1:1 | LL | union U { | ^^^^^^^ recursive type has infinite size LL | a: u8, -LL | b: U, - | - recursive without indirection +LL | b: std::mem::ManuallyDrop<U>, + | ------------------------- recursive without indirection | help: insert some indirection (e.g., a `Box`, `Rc`, or `&`) to make `U` representable | -LL | b: Box<U>, - | ++++ + +LL | b: Box<std::mem::ManuallyDrop<U>>, + | ++++ + 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<T: ?Sized> { - value: T, + value: ManuallyDrop<T>, //~^ ERROR the size for values of type } struct Foo2<T: ?Sized> { - value: T, + value: ManuallyDrop<T>, //~^ ERROR the size for values of type t: u32, } enum Foo3<T: ?Sized> { - Value(T), + Value(ManuallyDrop<T>), //~^ 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<T: ?Sized> { | - this type parameter needs to be `std::marker::Sized` -LL | value: T, - | ^ doesn't have a size known at compile-time +LL | value: ManuallyDrop<T>, + | ^^^^^^^^^^^^^^^ doesn't have a size known at compile-time | + = note: required because it appears within the type `ManuallyDrop<T>` = 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<T> { | help: borrowed types always have a statically known size | -LL | value: &T, +LL | value: &ManuallyDrop<T>, | + help: the `Box` type always has a statically known size and allocates its contents in the heap | -LL | value: Box<T>, - | ++++ + +LL | value: Box<ManuallyDrop<T>>, + | ++++ + 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<T: ?Sized> { | - this type parameter needs to be `std::marker::Sized` -LL | value: T, - | ^ doesn't have a size known at compile-time +LL | value: ManuallyDrop<T>, + | ^^^^^^^^^^^^^^^ doesn't have a size known at compile-time | + = note: required because it appears within the type `ManuallyDrop<T>` = 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<T> { | help: borrowed types always have a statically known size | -LL | value: &T, +LL | value: &ManuallyDrop<T>, | + help: the `Box` type always has a statically known size and allocates its contents in the heap | -LL | value: Box<T>, - | ++++ + +LL | value: Box<ManuallyDrop<T>>, + | ++++ + 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<T: ?Sized> { | - this type parameter needs to be `std::marker::Sized` -LL | Value(T), - | ^ doesn't have a size known at compile-time +LL | Value(ManuallyDrop<T>), + | ^^^^^^^^^^^^^^^ doesn't have a size known at compile-time | + = note: required because it appears within the type `ManuallyDrop<T>` = 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<T> { | help: borrowed types always have a statically known size | -LL | Value(&T), +LL | Value(&ManuallyDrop<T>), | + help: the `Box` type always has a statically known size and allocates its contents in the heap | -LL | Value(Box<T>), - | ++++ + +LL | Value(Box<ManuallyDrop<T>>), + | ++++ + 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..544213dbc5543 100644 --- a/src/test/ui/union/union-unsafe.mir.stderr +++ b/src/test/ui/union/union-unsafe.mir.stderr @@ -1,29 +1,13 @@ 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 | = 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 - | -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 - | - = 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 +15,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 +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:61:13 + --> $DIR/union-unsafe.rs:60:13 | LL | let a = u1.a; | ^^^^ access to union field @@ -47,7 +31,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 +39,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 +47,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 +55,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 +63,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 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 3cb3a18cb7544..5e1837a901d46 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>, i32), + a: (ManuallyDrop<RefCell<i32>>, 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); // 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 a8c3886657f43..f959fe5bdb5c5 100644 --- a/src/test/ui/union/union-unsafe.thir.stderr +++ b/src/test/ui/union/union-unsafe.thir.stderr @@ -1,29 +1,13 @@ 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 | = 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 - | -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 - | - = 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 +15,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 +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:61:13 + --> $DIR/union-unsafe.rs:60:13 | LL | let a = u1.a; | ^^^^ access to union field @@ -47,7 +31,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 +39,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 +47,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 +55,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 +63,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 9 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<str>, | ++++ + 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<str>, | ++++ + 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<NonCopy>, } 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<PizzaTopping> } #[allow(dead_code)] +#[derive(Clone, Copy)] enum PizzaTopping { Cheese, Pineapple, 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 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}"