do not apply DerefMut on union field
This commit is contained in:
parent
8ed5cb56b5
commit
ec0924f964
3 changed files with 39 additions and 1 deletions
|
@ -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;
|
||||
|
|
13
src/test/ui/union/union-deref.rs
Normal file
13
src/test/ui/union/union-deref.rs
Normal 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
|
||||
}
|
11
src/test/ui/union/union-deref.stderr
Normal file
11
src/test/ui/union/union-deref.stderr
Normal 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
|
||||
|
Loading…
Add table
Reference in a new issue