From ec7152cdf68506df2b316a47b113666d75712954 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 10 Jun 2022 22:12:57 -0700 Subject: [PATCH] allow unions with mutable references and tuples of allowed types --- compiler/rustc_passes/src/stability.rs | 27 +++++++++++++++---- .../feature-gate-untagged_unions.rs | 22 +++++++++++++-- .../feature-gate-untagged_unions.stderr | 22 +++++++++++---- 3 files changed, 59 insertions(+), 12 deletions(-) diff --git a/compiler/rustc_passes/src/stability.rs b/compiler/rustc_passes/src/stability.rs index a1697978d66..187a3f95d52 100644 --- a/compiler/rustc_passes/src/stability.rs +++ b/compiler/rustc_passes/src/stability.rs @@ -772,17 +772,27 @@ impl<'tcx> Visitor<'tcx> for Checker<'tcx> { let ty = self.tcx.type_of(item.def_id); let ty::Adt(adt_def, substs) = ty.kind() else { bug!() }; - #[allow(rustc::usage_of_qualified_ty)] // `Ty` is the wrong type here, we really want `ty::Ty`. + #[allow(rustc::usage_of_qualified_ty)] // `Ty` is `hir::Ty` here, we really want `ty::Ty`. fn allowed_union_field<'tcx>( tcx: TyCtxt<'tcx>, param_env: ty::ParamEnv<'tcx>, ty: ty::Ty<'tcx>, ) -> bool { - ty.ty_adt_def().map_or(false, |adt_def| adt_def.is_manually_drop()) - || ty.is_copy_modulo_regions(tcx.at(DUMMY_SP), param_env) + // We don't just accept all !needs_drop fields, due to semver concerns. + match ty.kind() { + ty::Ref(..) => true, // references never drop (even mutable refs, which are non-Copy and hence fail the later check) + ty::Tuple(tys) => { + // allow tuples of allowed types + tys.iter().all(|ty| allowed_union_field(tcx, param_env, ty)) + } + _ => { + ty.ty_adt_def().map_or(false, |adt_def| adt_def.is_manually_drop()) + || ty.is_copy_modulo_regions(tcx.at(DUMMY_SP), param_env) + } + } } - // Non-`Copy` fields are unstable, except for `ManuallyDrop`. + // `allowed_union_field` determines which fields are allowed on stable. let param_env = self.tcx.param_env(item.def_id); for field in &adt_def.non_enum_variant().fields { let field_ty = field.ty(self.tcx, substs); @@ -799,10 +809,17 @@ impl<'tcx> Visitor<'tcx> for Checker<'tcx> { &self.tcx.sess.parse_sess, sym::untagged_unions, self.tcx.def_span(field.did), - "unions with non-`Copy` fields other than `ManuallyDrop` are unstable", + "unions with non-`Copy` fields other than `ManuallyDrop`, \ + references, and tuples of such types are unstable", ) .emit(); } + } else { + // We allow this field. Make extra sure it does not drop. + assert!( + !field_ty.needs_drop(self.tcx, param_env), + "we should accept no maybe-dropping union fields" + ); } } } diff --git a/src/test/ui/feature-gates/feature-gate-untagged_unions.rs b/src/test/ui/feature-gates/feature-gate-untagged_unions.rs index af8d8e92b20..7bc5c42b775 100644 --- a/src/test/ui/feature-gates/feature-gate-untagged_unions.rs +++ b/src/test/ui/feature-gates/feature-gate-untagged_unions.rs @@ -1,4 +1,5 @@ // ignore-tidy-linelength +use std::mem::ManuallyDrop; union U1 { // OK a: u8, @@ -9,7 +10,11 @@ union U2 { // OK } union U22 { // OK - a: std::mem::ManuallyDrop, + a: ManuallyDrop, +} + +union U23 { // OK + a: (ManuallyDrop, i32), } union U3 { @@ -17,7 +22,7 @@ union U3 { } union U32 { // field that does not drop but is not `Copy`, either -- this is the real feature gate test! - a: std::cell::RefCell, //~ ERROR unions with non-`Copy` fields other than `ManuallyDrop` are unstable + a: std::cell::RefCell, //~ ERROR unions with non-`Copy` fields other than `ManuallyDrop`, references, and tuples of such types are unstable } union U4 { @@ -32,4 +37,17 @@ impl Drop for U5 { fn drop(&mut self) {} } +union U5Nested { // a nested union that drops is NOT OK + nest: U5, //~ ERROR unions cannot contain fields that may need dropping +} + +union U6 { // OK + s: &'static i32, + m: &'static mut i32, +} + +union U7 { // OK + f: (&'static mut i32, ManuallyDrop, i32), +} + fn main() {} diff --git a/src/test/ui/feature-gates/feature-gate-untagged_unions.stderr b/src/test/ui/feature-gates/feature-gate-untagged_unions.stderr index 9e4a89f80c8..e1f10c6de33 100644 --- a/src/test/ui/feature-gates/feature-gate-untagged_unions.stderr +++ b/src/test/ui/feature-gates/feature-gate-untagged_unions.stderr @@ -1,5 +1,5 @@ -error[E0658]: unions with non-`Copy` fields other than `ManuallyDrop` are unstable - --> $DIR/feature-gate-untagged_unions.rs:20:5 +error[E0658]: unions with non-`Copy` fields other than `ManuallyDrop`, references, and tuples of such types are unstable + --> $DIR/feature-gate-untagged_unions.rs:25:5 | LL | a: std::cell::RefCell, | ^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -8,7 +8,7 @@ LL | a: std::cell::RefCell, = help: add `#![feature(untagged_unions)]` to the crate attributes to enable error[E0740]: unions cannot contain fields that may need dropping - --> $DIR/feature-gate-untagged_unions.rs:16:5 + --> $DIR/feature-gate-untagged_unions.rs:21:5 | LL | a: String, | ^^^^^^^^^ @@ -20,7 +20,7 @@ LL | a: std::mem::ManuallyDrop, | +++++++++++++++++++++++ + error[E0740]: unions cannot contain fields that may need dropping - --> $DIR/feature-gate-untagged_unions.rs:24:5 + --> $DIR/feature-gate-untagged_unions.rs:29:5 | LL | a: T, | ^^^^ @@ -31,7 +31,19 @@ help: when the type does not implement `Copy`, wrap it inside a `ManuallyDrop<_> LL | a: std::mem::ManuallyDrop, | +++++++++++++++++++++++ + -error: aborting due to 3 previous errors +error[E0740]: unions cannot contain fields that may need dropping + --> $DIR/feature-gate-untagged_unions.rs:41:5 + | +LL | nest: U5, + | ^^^^^^^^ + | + = note: a type is guaranteed not to need dropping when it implements `Copy`, or when it is the special `ManuallyDrop<_>` type +help: when the type does not implement `Copy`, wrap it inside a `ManuallyDrop<_>` and ensure it is manually dropped + | +LL | nest: std::mem::ManuallyDrop, + | +++++++++++++++++++++++ + + +error: aborting due to 4 previous errors Some errors have detailed explanations: E0658, E0740. For more information about an error, try `rustc --explain E0658`.