about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--compiler/rustc_typeck/src/check/place_op.rs14
-rw-r--r--src/test/ui/union/union-deref.rs5
-rw-r--r--src/test/ui/union/union-deref.stderr12
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<T> { x:(), f: (ManuallyDrop<(T,)>,) }
 fn main() {
     let mut u : U1<Vec<i32>> = 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<Vec<i32>> = 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