Skip to content

Commit 83419e9

Browse files
committed
Call is_freeze less in unsafety-checking
This is to avoid cycles when calling `is_freeze` on an opaque type.
1 parent 7d5d374 commit 83419e9

File tree

2 files changed

+55
-16
lines changed

2 files changed

+55
-16
lines changed

src/librustc_mir/transform/check_unsafety.rs

Lines changed: 23 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -190,6 +190,16 @@ impl<'a, 'tcx> Visitor<'tcx> for UnsafetyChecker<'a, 'tcx> {
190190
}
191191

192192
fn visit_place(&mut self, place: &Place<'tcx>, context: PlaceContext, _location: Location) {
193+
// prevent
194+
// * `&mut x.field`
195+
// * `x.field = y;`
196+
// * `&x.field` if `field`'s type has interior mutability
197+
// because either of these would allow modifying the layout constrained field and
198+
// insert values that violate the layout constraints.
199+
if context.is_mutating_use() || context.is_borrow() {
200+
self.check_mut_borrowing_layout_constrained_field(place, context.is_mutating_use());
201+
}
202+
193203
for (i, elem) in place.projection.iter().enumerate() {
194204
let proj_base = &place.projection[..i];
195205

@@ -216,21 +226,6 @@ impl<'a, 'tcx> Visitor<'tcx> for UnsafetyChecker<'a, 'tcx> {
216226
);
217227
}
218228
}
219-
let is_borrow_of_interior_mut = context.is_borrow()
220-
&& !Place::ty_from(&place.local, proj_base, self.body, self.tcx).ty.is_freeze(
221-
self.tcx,
222-
self.param_env,
223-
self.source_info.span,
224-
);
225-
// prevent
226-
// * `&mut x.field`
227-
// * `x.field = y;`
228-
// * `&x.field` if `field`'s type has interior mutability
229-
// because either of these would allow modifying the layout constrained field and
230-
// insert values that violate the layout constraints.
231-
if context.is_mutating_use() || is_borrow_of_interior_mut {
232-
self.check_mut_borrowing_layout_constrained_field(place, context.is_mutating_use());
233-
}
234229
let old_source_info = self.source_info;
235230
if let (local, []) = (&place.local, proj_base) {
236231
let decl = &self.body.local_decls[*local];
@@ -412,6 +407,9 @@ impl<'a, 'tcx> UnsafetyChecker<'a, 'tcx> {
412407
cursor = proj_base;
413408

414409
match elem {
410+
// Modifications behind a dereference don't affect the value of
411+
// the pointer.
412+
ProjectionElem::Deref => return,
415413
ProjectionElem::Field(..) => {
416414
let ty =
417415
Place::ty_from(&place.local, proj_base, &self.body.local_decls, self.tcx)
@@ -426,14 +424,23 @@ impl<'a, 'tcx> UnsafetyChecker<'a, 'tcx> {
426424
"mutating layout constrained fields cannot statically be \
427425
checked for valid values",
428426
)
429-
} else {
427+
428+
// Check `is_freeze` as late as possible to avoid cycle errors
429+
// with opaque types.
430+
} else if !place.ty(self.body, self.tcx).ty.is_freeze(
431+
self.tcx,
432+
self.param_env,
433+
self.source_info.span,
434+
) {
430435
(
431436
"borrow of layout constrained field with interior \
432437
mutability",
433438
"references to fields of layout constrained fields \
434439
lose the constraints. Coupled with interior mutability, \
435440
the field can be changed to invalid values",
436441
)
442+
} else {
443+
continue;
437444
};
438445
let source_info = self.source_info;
439446
self.register_violations(
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
// Ensure that we don't get a cycle error from trying to determine whether an
2+
// opaque type implements `Freeze` in safety checking, when it doesn't matter.
3+
4+
// check-pass
5+
6+
#![feature(rustc_attrs)]
7+
8+
struct AnyValue<T>(T);
9+
10+
// No need to check for `Freeze` here, there's no
11+
// `rustc_layout_scalar_valid_range_start` involved.
12+
fn not_restricted(c: bool) -> impl Sized {
13+
if c {
14+
let x = AnyValue(not_restricted(false));
15+
&x.0;
16+
}
17+
2u32
18+
}
19+
20+
#[rustc_layout_scalar_valid_range_start(1)]
21+
struct NonZero<T>(T);
22+
23+
// No need to check for `Freeze` here, we're not borrowing the field.
24+
fn not_field(c: bool) -> impl Sized {
25+
if c {
26+
let x = unsafe { NonZero(not_field(false)) };
27+
&x;
28+
}
29+
5u32
30+
}
31+
32+
fn main() {}

0 commit comments

Comments
 (0)