about summary refs log tree commit diff
path: root/compiler
diff options
context:
space:
mode:
authorRalf Jung <post@ralfj.de>2020-08-16 10:07:33 +0200
committerRalf Jung <post@ralfj.de>2020-08-31 10:14:29 +0200
commitec0924f9649ea472782df6d21595714cb594f038 (patch)
tree469d6fd7fe103240d531fb4013f5a81cb0dd6e57 /compiler
parent8ed5cb56b5e5cc216eb6820a44dd4f7ef65107b0 (diff)
downloadrust-ec0924f9649ea472782df6d21595714cb594f038.tar.gz
rust-ec0924f9649ea472782df6d21595714cb594f038.zip
do not apply DerefMut on union field
Diffstat (limited to 'compiler')
-rw-r--r--compiler/rustc_typeck/src/check/place_op.rs16
1 files changed, 15 insertions, 1 deletions
diff --git a/compiler/rustc_typeck/src/check/place_op.rs b/compiler/rustc_typeck/src/check/place_op.rs
index 4bef9aecd2e..be2bc491c31 100644
--- a/compiler/rustc_typeck/src/check/place_op.rs
+++ b/compiler/rustc_typeck/src/check/place_op.rs
@@ -193,7 +193,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
     /// Convert auto-derefs, indices, etc of an expression from `Deref` and `Index`
     /// into `DerefMut` and `IndexMut` respectively.
     ///
-    /// This is a second pass of typechecking derefs/indices. We need this we do not
+    /// This is a second pass of typechecking derefs/indices. We need this because we do not
     /// always know whether a place needs to be mutable or not in the first pass.
     /// This happens whether there is an implicit mutable reborrow, e.g. when the type
     /// is used as the receiver of a method call.
@@ -236,6 +236,20 @@ 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 let hir::ExprKind::Field(ref outer_expr, _) = expr.kind {
+                                let ty = self.node_ty(outer_expr.hir_id);
+                                if ty.ty_adt_def().map_or(false, |adt| adt.is_union()) {
+                                    let mut err = self.tcx.sess.struct_span_err(
+                                        expr.span,
+                                        "not automatically applying `DerefMut` on union field",
+                                    );
+                                    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();
+                                }
+                            }
                         }
                     }
                     source = adjustment.target;