also detect DerefMut in nested union fields
This commit is contained in:
parent
ec0924f964
commit
44defaea3a
3 changed files with 36 additions and 16 deletions
|
@ -211,13 +211,21 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||||
debug!("convert_place_derefs_to_mutable: exprs={:?}", exprs);
|
debug!("convert_place_derefs_to_mutable: exprs={:?}", exprs);
|
||||||
|
|
||||||
// Fix up autoderefs and derefs.
|
// Fix up autoderefs and derefs.
|
||||||
|
let mut inside_union = false;
|
||||||
for (i, &expr) in exprs.iter().rev().enumerate() {
|
for (i, &expr) in exprs.iter().rev().enumerate() {
|
||||||
debug!("convert_place_derefs_to_mutable: i={} expr={:?}", i, expr);
|
debug!("convert_place_derefs_to_mutable: i={} expr={:?}", i, expr);
|
||||||
|
|
||||||
|
let mut source = self.node_ty(expr.hir_id);
|
||||||
|
if matches!(expr.kind, hir::ExprKind::Unary(hir::UnOp::UnDeref, _)) {
|
||||||
|
// Clear previous flag; after a pointer indirection it does not apply any more.
|
||||||
|
inside_union = false;
|
||||||
|
}
|
||||||
|
if source.ty_adt_def().map_or(false, |adt| adt.is_union()) {
|
||||||
|
inside_union = true;
|
||||||
|
}
|
||||||
// Fix up the autoderefs. Autorefs can only occur immediately preceding
|
// Fix up the autoderefs. Autorefs can only occur immediately preceding
|
||||||
// overloaded place ops, and will be fixed by them in order to get
|
// overloaded place ops, and will be fixed by them in order to get
|
||||||
// the correct region.
|
// the correct region.
|
||||||
let mut source = self.node_ty(expr.hir_id);
|
|
||||||
// Do not mutate adjustments in place, but rather take them,
|
// Do not mutate adjustments in place, but rather take them,
|
||||||
// and replace them after mutating them, to avoid having the
|
// and replace them after mutating them, to avoid having the
|
||||||
// typeck results borrowed during (`deref_mut`) method resolution.
|
// typeck results borrowed during (`deref_mut`) method resolution.
|
||||||
|
@ -238,17 +246,14 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||||
}
|
}
|
||||||
// If this is a union field, also throw an error.
|
// If this is a union field, also throw an error.
|
||||||
// Union fields should not get mutable auto-deref'd (see RFC 2514).
|
// Union fields should not get mutable auto-deref'd (see RFC 2514).
|
||||||
if let hir::ExprKind::Field(ref outer_expr, _) = expr.kind {
|
if inside_union {
|
||||||
let ty = self.node_ty(outer_expr.hir_id);
|
let mut err = self.tcx.sess.struct_span_err(
|
||||||
if ty.ty_adt_def().map_or(false, |adt| adt.is_union()) {
|
expr.span,
|
||||||
let mut err = self.tcx.sess.struct_span_err(
|
"not automatically applying `DerefMut` on union field",
|
||||||
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.help("writing to this field calls the destructor for the old value");
|
err.emit();
|
||||||
err.help("add an explicit `*` if that is desired, or call `ptr::write` to not run the destructor");
|
|
||||||
err.emit();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,10 +4,16 @@
|
||||||
|
|
||||||
use std::mem::ManuallyDrop;
|
use std::mem::ManuallyDrop;
|
||||||
|
|
||||||
union U<T> { x:(), f: ManuallyDrop<(T,)> }
|
union U1<T> { x:(), f: ManuallyDrop<(T,)> }
|
||||||
|
|
||||||
|
union U2<T> { x:(), f: (ManuallyDrop<(T,)>,) }
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
let mut u : U<Vec<i32>> = U { x: () };
|
let mut u : U1<Vec<i32>> = U1 { x: () };
|
||||||
unsafe { (*u.f).0 = Vec::new() }; // explicit deref, this compiles
|
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 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
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
error: not automatically applying `DerefMut` on union field
|
error: not automatically applying `DerefMut` on union field
|
||||||
--> $DIR/union-deref.rs:12:14
|
--> $DIR/union-deref.rs:14:14
|
||||||
|
|
|
|
||||||
LL | unsafe { u.f.0 = Vec::new() };
|
LL | unsafe { u.f.0 = Vec::new() };
|
||||||
| ^^^
|
| ^^^
|
||||||
|
@ -7,5 +7,14 @@ LL | unsafe { u.f.0 = Vec::new() };
|
||||||
= help: writing to this field calls the destructor for the old value
|
= 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
|
= help: add an explicit `*` if that is desired, or call `ptr::write` to not run the destructor
|
||||||
|
|
||||||
error: aborting due to previous error
|
error: not automatically applying `DerefMut` on union field
|
||||||
|
--> $DIR/union-deref.rs:18:14
|
||||||
|
|
|
||||||
|
LL | unsafe { u.f.0.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 2 previous errors
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue