From 97974e3cabefe725b6bea24c20e5fb9709e08a02 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 16 Aug 2020 10:32:37 +0200 Subject: [PATCH] only emit error for ManuallyDrop derefs --- compiler/rustc_typeck/src/check/place_op.rs | 14 +++++++++----- src/test/ui/union/union-deref.rs | 5 +++-- src/test/ui/union/union-deref.stderr | 12 ++++++------ 3 files changed, 18 insertions(+), 13 deletions(-) diff --git a/compiler/rustc_typeck/src/check/place_op.rs b/compiler/rustc_typeck/src/check/place_op.rs index 54b3fdd837e..c6d5c934a7e 100644 --- a/compiler/rustc_typeck/src/check/place_op.rs +++ b/compiler/rustc_typeck/src/check/place_op.rs @@ -244,14 +244,18 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { if let ty::Ref(region, _, mutbl) = method.sig.output().kind { *deref = OverloadedDeref { region, mutbl }; } - // If this is a union field, also throw an error. - // Union fields should not get mutable auto-deref'd (see RFC 2514). - if inside_union { + // If this is a union field, also throw an error for `DerefMut` of `ManuallyDrop` (see RFC 2514). + // This helps avoid accidental drops. + if inside_union + && source.ty_adt_def().map_or(false, |adt| adt.is_manually_drop()) + { let mut err = self.tcx.sess.struct_span_err( expr.span, - "not automatically applying `DerefMut` on union field", + "not automatically applying `DerefMut` on `ManuallyDrop` union field", + ); + err.help( + "writing to this reference calls the destructor for the old value", ); - err.help("writing to this field calls the destructor for the old value"); err.help("add an explicit `*` if that is desired, or call `ptr::write` to not run the destructor"); err.emit(); } diff --git a/src/test/ui/union/union-deref.rs b/src/test/ui/union/union-deref.rs index 4578110cd54..d789659a807 100644 --- a/src/test/ui/union/union-deref.rs +++ b/src/test/ui/union/union-deref.rs @@ -1,3 +1,4 @@ +// ignore-tidy-linelength //! Test the part of RFC 2514 that is about not applying `DerefMut` coercions //! of union fields. #![feature(untagged_unions)] @@ -11,9 +12,9 @@ union U2 { x:(), f: (ManuallyDrop<(T,)>,) } fn main() { let mut u : U1> = U1 { x: () }; unsafe { (*u.f).0 = Vec::new() }; // explicit deref, this compiles - unsafe { u.f.0 = Vec::new() }; //~ERROR not automatically applying `DerefMut` on union field + unsafe { u.f.0 = Vec::new() }; //~ERROR not automatically applying `DerefMut` on `ManuallyDrop` union field let mut u : U2> = U2 { x: () }; unsafe { (*u.f.0).0 = Vec::new() }; // explicit deref, this compiles - unsafe { u.f.0.0 = Vec::new() }; //~ERROR not automatically applying `DerefMut` on union field + unsafe { u.f.0.0 = Vec::new() }; //~ERROR not automatically applying `DerefMut` on `ManuallyDrop` union field } diff --git a/src/test/ui/union/union-deref.stderr b/src/test/ui/union/union-deref.stderr index 93374436d2f..03428489318 100644 --- a/src/test/ui/union/union-deref.stderr +++ b/src/test/ui/union/union-deref.stderr @@ -1,19 +1,19 @@ -error: not automatically applying `DerefMut` on union field - --> $DIR/union-deref.rs:14:14 +error: not automatically applying `DerefMut` on `ManuallyDrop` union field + --> $DIR/union-deref.rs:15:14 | LL | unsafe { u.f.0 = Vec::new() }; | ^^^ | - = help: writing to this field calls the destructor for the old value + = help: writing to this reference calls the destructor for the old value = help: add an explicit `*` if that is desired, or call `ptr::write` to not run the destructor -error: not automatically applying `DerefMut` on union field - --> $DIR/union-deref.rs:18:14 +error: not automatically applying `DerefMut` on `ManuallyDrop` union field + --> $DIR/union-deref.rs:19:14 | LL | unsafe { u.f.0.0 = Vec::new() }; | ^^^^^^^ | - = help: writing to this field calls the destructor for the old value + = help: writing to this reference calls the destructor for the old value = help: add an explicit `*` if that is desired, or call `ptr::write` to not run the destructor error: aborting due to 2 previous errors