only emit error for ManuallyDrop derefs

This commit is contained in:
Ralf Jung 2020-08-16 10:32:37 +02:00
parent 44defaea3a
commit 97974e3cab
3 changed files with 18 additions and 13 deletions

View File

@ -244,14 +244,18 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
if let ty::Ref(region, _, mutbl) = method.sig.output().kind { if let ty::Ref(region, _, mutbl) = method.sig.output().kind {
*deref = OverloadedDeref { region, mutbl }; *deref = OverloadedDeref { region, mutbl };
} }
// If this is a union field, also throw an error. // If this is a union field, also throw an error for `DerefMut` of `ManuallyDrop` (see RFC 2514).
// Union fields should not get mutable auto-deref'd (see RFC 2514). // This helps avoid accidental drops.
if inside_union { if inside_union
&& source.ty_adt_def().map_or(false, |adt| adt.is_manually_drop())
{
let mut err = self.tcx.sess.struct_span_err( let mut err = self.tcx.sess.struct_span_err(
expr.span, 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.help("add an explicit `*` if that is desired, or call `ptr::write` to not run the destructor");
err.emit(); err.emit();
} }

View File

@ -1,3 +1,4 @@
// ignore-tidy-linelength
//! Test the part of RFC 2514 that is about not applying `DerefMut` coercions //! Test the part of RFC 2514 that is about not applying `DerefMut` coercions
//! of union fields. //! of union fields.
#![feature(untagged_unions)] #![feature(untagged_unions)]
@ -11,9 +12,9 @@ union U2<T> { x:(), f: (ManuallyDrop<(T,)>,) }
fn main() { fn main() {
let mut u : U1<Vec<i32>> = U1 { 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 `ManuallyDrop` union field
let mut u : U2<Vec<i32>> = U2 { x: () }; 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() }; // 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
} }

View File

@ -1,19 +1,19 @@
error: not automatically applying `DerefMut` on union field error: not automatically applying `DerefMut` on `ManuallyDrop` union field
--> $DIR/union-deref.rs:14:14 --> $DIR/union-deref.rs:15:14
| |
LL | unsafe { u.f.0 = Vec::new() }; 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 = 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 error: not automatically applying `DerefMut` on `ManuallyDrop` union field
--> $DIR/union-deref.rs:18:14 --> $DIR/union-deref.rs:19:14
| |
LL | unsafe { u.f.0.0 = Vec::new() }; 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 = help: add an explicit `*` if that is desired, or call `ptr::write` to not run the destructor
error: aborting due to 2 previous errors error: aborting due to 2 previous errors