1
Fork 0

consider assignments of union field of ManuallyDrop type safe

This commit is contained in:
Ralf Jung 2020-10-18 13:53:54 +02:00
parent 3d3c8c5e0d
commit 3ac1df8b99
4 changed files with 35 additions and 56 deletions

View file

@ -46,7 +46,7 @@ pub enum UnsafetyViolationDetails {
UseOfMutableStatic, UseOfMutableStatic,
UseOfExternStatic, UseOfExternStatic,
DerefOfRawPointer, DerefOfRawPointer,
AssignToNonCopyUnionField, AssignToDroppingUnionField,
AccessToUnionField, AccessToUnionField,
MutationOfLayoutConstrainedField, MutationOfLayoutConstrainedField,
BorrowOfLayoutConstrainedField, BorrowOfLayoutConstrainedField,
@ -94,8 +94,8 @@ impl UnsafetyViolationDetails {
"raw pointers may be NULL, dangling or unaligned; they can violate aliasing rules \ "raw pointers may be NULL, dangling or unaligned; they can violate aliasing rules \
and cause data races: all of these are undefined behavior", and cause data races: all of these are undefined behavior",
), ),
AssignToNonCopyUnionField => ( AssignToDroppingUnionField => (
"assignment to non-`Copy` union field", "assignment to union field that needs dropping",
"the previous content of the field will be dropped, which causes undefined \ "the previous content of the field will be dropped, which causes undefined \
behavior if the field was not properly initialized", behavior if the field was not properly initialized",
), ),

View file

@ -235,37 +235,40 @@ impl<'a, 'tcx> Visitor<'tcx> for UnsafetyChecker<'a, 'tcx> {
UnsafetyViolationKind::GeneralAndConstFn, UnsafetyViolationKind::GeneralAndConstFn,
UnsafetyViolationDetails::DerefOfRawPointer, UnsafetyViolationDetails::DerefOfRawPointer,
), ),
ty::Adt(adt, _) => { ty::Adt(adt, _) if adt.is_union() => {
if adt.is_union() { if context == PlaceContext::MutatingUse(MutatingUseContext::Store)
if context == PlaceContext::MutatingUse(MutatingUseContext::Store) || context == PlaceContext::MutatingUse(MutatingUseContext::Drop)
|| context == PlaceContext::MutatingUse(MutatingUseContext::Drop) || context == PlaceContext::MutatingUse(MutatingUseContext::AsmOutput)
|| context == PlaceContext::MutatingUse(MutatingUseContext::AsmOutput) {
{ let elem_ty = match elem {
let elem_ty = match elem { ProjectionElem::Field(_, ty) => ty,
ProjectionElem::Field(_, ty) => ty, _ => span_bug!(
_ => span_bug!( self.source_info.span,
self.source_info.span, "non-field projection {:?} from union?",
"non-field projection {:?} from union?", place
place ),
), };
}; let manually_drop = elem_ty
if !elem_ty.is_copy_modulo_regions( .ty_adt_def()
.map_or(false, |adt_def| adt_def.is_manually_drop());
let nodrop = manually_drop
|| elem_ty.is_copy_modulo_regions(
self.tcx.at(self.source_info.span), self.tcx.at(self.source_info.span),
self.param_env, self.param_env,
) { );
self.require_unsafe( if !nodrop {
UnsafetyViolationKind::GeneralAndConstFn,
UnsafetyViolationDetails::AssignToNonCopyUnionField,
)
} else {
// write to non-move union, safe
}
} else {
self.require_unsafe( self.require_unsafe(
UnsafetyViolationKind::GeneralAndConstFn, UnsafetyViolationKind::GeneralAndConstFn,
UnsafetyViolationDetails::AccessToUnionField, UnsafetyViolationDetails::AssignToDroppingUnionField,
) )
} else {
// write to non-drop union field, safe
} }
} else {
self.require_unsafe(
UnsafetyViolationKind::GeneralAndConstFn,
UnsafetyViolationDetails::AccessToUnionField,
)
} }
} }
_ => {} _ => {}

View file

@ -18,7 +18,7 @@ union U4<T: Copy> {
fn generic_noncopy<T: Default>() { fn generic_noncopy<T: Default>() {
let mut u3 = U3 { a: ManuallyDrop::new(T::default()) }; let mut u3 = U3 { a: ManuallyDrop::new(T::default()) };
u3.a = ManuallyDrop::new(T::default()); //~ ERROR assignment to non-`Copy` union field is unsafe u3.a = ManuallyDrop::new(T::default()); // OK (assignment does not drop)
*u3.a = T::default(); //~ ERROR access to union field is unsafe *u3.a = T::default(); //~ ERROR access to union field is unsafe
} }
@ -41,7 +41,7 @@ fn main() {
// let U1 { .. } = u1; // OK // let U1 { .. } = u1; // OK
let mut u2 = U2 { a: ManuallyDrop::new(String::from("old")) }; // OK let mut u2 = U2 { a: ManuallyDrop::new(String::from("old")) }; // OK
u2.a = ManuallyDrop::new(String::from("new")); //~ ERROR assignment to non-`Copy` union u2.a = ManuallyDrop::new(String::from("new")); // OK (assignment does not drop)
*u2.a = String::from("new"); //~ ERROR access to union field is unsafe *u2.a = String::from("new"); //~ ERROR access to union field is unsafe
let mut u3 = U3 { a: ManuallyDrop::new(0) }; // OK let mut u3 = U3 { a: ManuallyDrop::new(0) }; // OK
@ -49,6 +49,6 @@ fn main() {
*u3.a = 1; //~ ERROR access to union field is unsafe *u3.a = 1; //~ ERROR access to union field is unsafe
let mut u3 = U3 { a: ManuallyDrop::new(String::from("old")) }; // OK let mut u3 = U3 { a: ManuallyDrop::new(String::from("old")) }; // OK
u3.a = ManuallyDrop::new(String::from("new")); //~ ERROR assignment to non-`Copy` union u3.a = ManuallyDrop::new(String::from("new")); // OK (assignment does not drop)
*u3.a = String::from("new"); //~ ERROR access to union field is unsafe *u3.a = String::from("new"); //~ ERROR access to union field is unsafe
} }

View file

@ -1,11 +1,3 @@
error[E0133]: assignment to non-`Copy` union field is unsafe and requires unsafe function or block
--> $DIR/union-unsafe.rs:21:5
|
LL | u3.a = ManuallyDrop::new(T::default());
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ assignment to non-`Copy` union field
|
= note: the previous content of the field will be dropped, which causes undefined behavior if the field was not properly initialized
error[E0133]: access to union field is unsafe and requires unsafe function or block error[E0133]: access to union field is unsafe and requires unsafe function or block
--> $DIR/union-unsafe.rs:22:6 --> $DIR/union-unsafe.rs:22:6
| |
@ -46,14 +38,6 @@ LL | if let U1 { a: 12 } = u1 {}
| |
= note: the field may not be properly initialized: using uninitialized data will cause undefined behavior = note: the field may not be properly initialized: using uninitialized data will cause undefined behavior
error[E0133]: assignment to non-`Copy` union field is unsafe and requires unsafe function or block
--> $DIR/union-unsafe.rs:44:5
|
LL | u2.a = ManuallyDrop::new(String::from("new"));
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ assignment to non-`Copy` union field
|
= note: the previous content of the field will be dropped, which causes undefined behavior if the field was not properly initialized
error[E0133]: access to union field is unsafe and requires unsafe function or block error[E0133]: access to union field is unsafe and requires unsafe function or block
--> $DIR/union-unsafe.rs:45:6 --> $DIR/union-unsafe.rs:45:6
| |
@ -70,14 +54,6 @@ LL | *u3.a = 1;
| |
= note: the field may not be properly initialized: using uninitialized data will cause undefined behavior = note: the field may not be properly initialized: using uninitialized data will cause undefined behavior
error[E0133]: assignment to non-`Copy` union field is unsafe and requires unsafe function or block
--> $DIR/union-unsafe.rs:52:5
|
LL | u3.a = ManuallyDrop::new(String::from("new"));
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ assignment to non-`Copy` union field
|
= note: the previous content of the field will be dropped, which causes undefined behavior if the field was not properly initialized
error[E0133]: access to union field is unsafe and requires unsafe function or block error[E0133]: access to union field is unsafe and requires unsafe function or block
--> $DIR/union-unsafe.rs:53:6 --> $DIR/union-unsafe.rs:53:6
| |
@ -86,6 +62,6 @@ LL | *u3.a = String::from("new");
| |
= note: the field may not be properly initialized: using uninitialized data will cause undefined behavior = note: the field may not be properly initialized: using uninitialized data will cause undefined behavior
error: aborting due to 11 previous errors error: aborting due to 8 previous errors
For more information about this error, try `rustc --explain E0133`. For more information about this error, try `rustc --explain E0133`.