diff --git a/src/librustc_mir/transform/check_unsafety.rs b/src/librustc_mir/transform/check_unsafety.rs index c7a785ad2c5..b124f8b1c0b 100644 --- a/src/librustc_mir/transform/check_unsafety.rs +++ b/src/librustc_mir/transform/check_unsafety.rs @@ -187,13 +187,15 @@ impl<'a, 'tcx> Visitor<'tcx> for UnsafetyChecker<'a, 'tcx> { kind: UnsafetyViolationKind::BorrowPacked(lint_root) }], &[]); } - let is_freeze = base - .ty(self.mir, self.tcx) - .to_ty(self.tcx) - .is_freeze(self.tcx, self.param_env, self.source_info.span); - if context.is_mutating_use() || !is_freeze { - self.check_mut_borrowing_layout_constrained_field(place); - } + } + let is_borrow_of_interior_mut = context.is_borrow() && !base + .ty(self.mir, self.tcx) + .to_ty(self.tcx) + .is_freeze(self.tcx, self.param_env, self.source_info.span); + if context.is_mutating_use() || is_borrow_of_interior_mut { + self.check_mut_borrowing_layout_constrained_field( + place, context.is_mutating_use(), + ); } let old_source_info = self.source_info; if let &Place::Local(local) = base { @@ -360,6 +362,7 @@ impl<'a, 'tcx> UnsafetyChecker<'a, 'tcx> { fn check_mut_borrowing_layout_constrained_field( &mut self, mut place: &Place<'tcx>, + is_mut_use: bool, ) { while let &Place::Projection(box Projection { ref base, ref elem @@ -371,17 +374,26 @@ impl<'a, 'tcx> UnsafetyChecker<'a, 'tcx> { ty::Adt(def, _) => match self.tcx.layout_scalar_valid_range(def.did) { (Bound::Unbounded, Bound::Unbounded) => {}, _ => { + let (description, details) = if is_mut_use { + ( + "mutation of layout constrained field", + "mutating layout constrained fields cannot statically be \ + checked for valid values", + ) + } else { + ( + "borrow of layout constrained field with interior \ + mutability", + "references to fields of layout constrained fields \ + lose the constraints. Coupled with interior mutability, \ + the field can be changed to invalid values", + ) + }; let source_info = self.source_info; self.register_violations(&[UnsafetyViolation { source_info, - description: Symbol::intern( - "borrow of layout constrained field", - ).as_interned_str(), - details: - Symbol::intern( - "references to fields of layout constrained fields \ - lose the constraints", - ).as_interned_str(), + description: Symbol::intern(description).as_interned_str(), + details: Symbol::intern(details).as_interned_str(), kind: UnsafetyViolationKind::MinConstFn, }], &[]); } diff --git a/src/test/ui/unsafe/ranged_ints2.rs b/src/test/ui/unsafe/ranged_ints2.rs index 3738b7f5af4..68ba120b279 100644 --- a/src/test/ui/unsafe/ranged_ints2.rs +++ b/src/test/ui/unsafe/ranged_ints2.rs @@ -5,5 +5,5 @@ pub(crate) struct NonZero(pub(crate) T); fn main() { let mut x = unsafe { NonZero(1) }; - let y = &mut x.0; //~ ERROR borrow of layout constrained field is unsafe + let y = &mut x.0; //~ ERROR mutation of layout constrained field is unsafe } diff --git a/src/test/ui/unsafe/ranged_ints2.stderr b/src/test/ui/unsafe/ranged_ints2.stderr index 77313f27a42..ae63f47ed74 100644 --- a/src/test/ui/unsafe/ranged_ints2.stderr +++ b/src/test/ui/unsafe/ranged_ints2.stderr @@ -1,10 +1,10 @@ -error[E0133]: borrow of layout constrained field is unsafe and requires unsafe function or block +error[E0133]: mutation of layout constrained field is unsafe and requires unsafe function or block --> $DIR/ranged_ints2.rs:8:13 | -LL | let y = &mut x.0; //~ ERROR borrow of layout constrained field is unsafe - | ^^^^^^^^ borrow of layout constrained field +LL | let y = &mut x.0; //~ ERROR mutation of layout constrained field is unsafe + | ^^^^^^^^ mutation of layout constrained field | - = note: references to fields of layout constrained fields lose the constraints + = note: mutating layout constrained fields cannot statically be checked for valid values error: aborting due to previous error diff --git a/src/test/ui/unsafe/ranged_ints3.rs b/src/test/ui/unsafe/ranged_ints3.rs index d68c712227a..47d67fac678 100644 --- a/src/test/ui/unsafe/ranged_ints3.rs +++ b/src/test/ui/unsafe/ranged_ints3.rs @@ -7,5 +7,5 @@ use std::cell::Cell; pub(crate) struct NonZero(pub(crate) T); fn main() { let mut x = unsafe { NonZero(Cell::new(1)) }; - let y = &x.0; //~ ERROR borrow of layout constrained field is unsafe + let y = &x.0; //~ ERROR borrow of layout constrained field with interior mutability } diff --git a/src/test/ui/unsafe/ranged_ints3.stderr b/src/test/ui/unsafe/ranged_ints3.stderr index b5aa9089b5f..311a058fdb0 100644 --- a/src/test/ui/unsafe/ranged_ints3.stderr +++ b/src/test/ui/unsafe/ranged_ints3.stderr @@ -1,10 +1,10 @@ -error[E0133]: borrow of layout constrained field is unsafe and requires unsafe function or block +error[E0133]: borrow of layout constrained field with interior mutability is unsafe and requires unsafe function or block --> $DIR/ranged_ints3.rs:10:13 | -LL | let y = &x.0; //~ ERROR borrow of layout constrained field is unsafe - | ^^^^ borrow of layout constrained field +LL | let y = &x.0; //~ ERROR borrow of layout constrained field with interior mutability + | ^^^^ borrow of layout constrained field with interior mutability | - = note: references to fields of layout constrained fields lose the constraints + = note: references to fields of layout constrained fields lose the constraints. Coupled with interior mutability, the field can be changed to invalid values error: aborting due to previous error diff --git a/src/test/ui/unsafe/ranged_ints4.rs b/src/test/ui/unsafe/ranged_ints4.rs new file mode 100644 index 00000000000..d8632c48434 --- /dev/null +++ b/src/test/ui/unsafe/ranged_ints4.rs @@ -0,0 +1,9 @@ +#![feature(rustc_attrs)] + +#[rustc_layout_scalar_valid_range_start(1)] +#[repr(transparent)] +pub(crate) struct NonZero(pub(crate) T); +fn main() { + let mut x = unsafe { NonZero(1) }; + x.0 = 0; //~ ERROR mutation of layout constrained field is unsafe +} diff --git a/src/test/ui/unsafe/ranged_ints4.stderr b/src/test/ui/unsafe/ranged_ints4.stderr new file mode 100644 index 00000000000..c6468b643b4 --- /dev/null +++ b/src/test/ui/unsafe/ranged_ints4.stderr @@ -0,0 +1,11 @@ +error[E0133]: mutation of layout constrained field is unsafe and requires unsafe function or block + --> $DIR/ranged_ints4.rs:8:5 + | +LL | x.0 = 0; //~ ERROR mutation of layout constrained field is unsafe + | ^^^^^^^ mutation of layout constrained field + | + = note: mutating layout constrained fields cannot statically be checked for valid values + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0133`.