do not apply DerefMut on union field

This commit is contained in:
Ralf Jung 2020-08-16 10:07:33 +02:00
parent 8ed5cb56b5
commit ec0924f964
3 changed files with 39 additions and 1 deletions

View File

@ -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;

View File

@ -0,0 +1,13 @@
//! Test the part of RFC 2514 that is about not applying `DerefMut` coercions
//! of union fields.
#![feature(untagged_unions)]
use std::mem::ManuallyDrop;
union U<T> { x:(), f: ManuallyDrop<(T,)> }
fn main() {
let mut u : U<Vec<i32>> = U { 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
}

View File

@ -0,0 +1,11 @@
error: not automatically applying `DerefMut` on union field
--> $DIR/union-deref.rs:12:14
|
LL | unsafe { u.f.0 = Vec::new() };
| ^^^
|
= help: writing to this field 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 previous error