Skip to content

Commit 226664b

Browse files
committed
Prevent dependency cycle with -Zthir-unsafeck
1 parent 71a6c7c commit 226664b

File tree

2 files changed

+51
-19
lines changed

2 files changed

+51
-19
lines changed

compiler/rustc_mir_build/src/check_unsafety.rs

+36-19
Original file line numberDiff line numberDiff line change
@@ -399,21 +399,31 @@ impl<'a, 'tcx> Visitor<'a, 'tcx> for UnsafetyVisitor<'a, 'tcx> {
399399
fake_reads: _,
400400
} => {
401401
let closure_id = closure_id.expect_local();
402-
let closure_def = if let Some((did, const_param_id)) =
403-
ty::WithOptConstParam::try_lookup(closure_id, self.tcx)
404-
{
405-
ty::WithOptConstParam { did, const_param_did: Some(const_param_id) }
406-
} else {
407-
ty::WithOptConstParam::unknown(closure_id)
408-
};
409-
let (closure_thir, expr) = self.tcx.thir_body(closure_def);
410-
let closure_thir = &closure_thir.borrow();
411-
let hir_context = self.tcx.hir().local_def_id_to_hir_id(closure_id);
412-
let mut closure_visitor =
413-
UnsafetyVisitor { thir: closure_thir, hir_context, ..*self };
414-
closure_visitor.visit_expr(&closure_thir[expr]);
415-
// Unsafe blocks can be used in closures, make sure to take it into account
416-
self.safety_context = closure_visitor.safety_context;
402+
let closure_hir_id = self.tcx.hir().local_def_id_to_hir_id(closure_id);
403+
404+
// Closures in AnonConsts are handled separately to avoid cycles (issue #87414).
405+
if !matches!(
406+
self.tcx.hir().get(self.tcx.hir().enclosing_body_owner(closure_hir_id)),
407+
hir::Node::AnonConst(_)
408+
) {
409+
let closure_def = if let Some((did, const_param_id)) =
410+
ty::WithOptConstParam::try_lookup(closure_id, self.tcx)
411+
{
412+
ty::WithOptConstParam { did, const_param_did: Some(const_param_id) }
413+
} else {
414+
ty::WithOptConstParam::unknown(closure_id)
415+
};
416+
let (closure_thir, expr) = self.tcx.thir_body(closure_def);
417+
let closure_thir = &closure_thir.borrow();
418+
let mut closure_visitor = UnsafetyVisitor {
419+
thir: closure_thir,
420+
hir_context: closure_hir_id,
421+
..*self
422+
};
423+
closure_visitor.visit_expr(&closure_thir[expr]);
424+
// Unsafe blocks can be used in closures, make sure to take it into account
425+
self.safety_context = closure_visitor.safety_context;
426+
}
417427
}
418428
ExprKind::Field { lhs, .. } => {
419429
let lhs = &self.thir[lhs];
@@ -597,11 +607,19 @@ pub fn check_unsafety<'tcx>(tcx: TyCtxt<'tcx>, def: ty::WithOptConstParam<LocalD
597607
return;
598608
}
599609

600-
// Closures are handled by their owner, if it has a body
610+
let hir_id = tcx.hir().local_def_id_to_hir_id(def.did);
611+
612+
// Closures are handled by their owner, if it has a body, except if the
613+
// closure occurs in an AnonConst body to avoid a cycle (issue #87414)
601614
if tcx.is_closure(def.did.to_def_id()) {
602-
let owner = tcx.hir().local_def_id_to_hir_id(def.did).owner;
603-
let owner_hir_id = tcx.hir().local_def_id_to_hir_id(owner);
615+
let encl_body_owner = tcx.hir().enclosing_body_owner(hir_id);
616+
if matches!(tcx.hir().get(encl_body_owner), hir::Node::AnonConst(_)) {
617+
tcx.ensure().thir_check_unsafety(tcx.hir().local_def_id(encl_body_owner));
618+
return;
619+
}
604620

621+
let owner = hir_id.owner;
622+
let owner_hir_id = tcx.hir().local_def_id_to_hir_id(owner);
605623
if tcx.hir().maybe_body_owned_by(owner_hir_id).is_some() {
606624
tcx.ensure().thir_check_unsafety(owner);
607625
return;
@@ -615,7 +633,6 @@ pub fn check_unsafety<'tcx>(tcx: TyCtxt<'tcx>, def: ty::WithOptConstParam<LocalD
615633
return;
616634
}
617635

618-
let hir_id = tcx.hir().local_def_id_to_hir_id(def.did);
619636
let body_unsafety = tcx.hir().fn_sig_by_hir_id(hir_id).map_or(BodyUnsafety::Safe, |fn_sig| {
620637
if fn_sig.header.unsafety == hir::Unsafety::Unsafe {
621638
BodyUnsafety::Unsafe(fn_sig.span)
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
// Regression test for #87414.
2+
3+
// check-pass
4+
// compile-flags: -Zthir-unsafeck
5+
6+
fn bad<T>() -> Box<dyn Iterator<Item = [(); { |x: u32| { x }; 4 }]>> { todo!() }
7+
8+
fn foo() -> [(); { |x: u32| { x }; 4 }] { todo!() }
9+
fn bar() { let _: [(); { |x: u32| { x }; 4 }]; }
10+
11+
// This one should not cause any errors either:
12+
unsafe fn unsf() {}
13+
fn bad2<T>() -> Box<dyn Iterator<Item = [(); { unsafe { || { unsf() } }; 4 }]>> { todo!() }
14+
15+
fn main() {}

0 commit comments

Comments
 (0)