Skip to content

Commit 62ab2c2

Browse files
committed
Fix ICE when late-bound lifetimes don't appear in fn signature
PR #135479 changed how late-bound regions are registered for MIR borrowck, switching from `for_each_late_bound_region_in_item` to iterating over `bound_inputs_and_output.bound_vars()`. However, for regular functions, the latter only includes late-bound lifetimes that appear in the function's inputs or output, missing unused lifetime parameters. This caused an ICE when `replace_bound_regions_with_nll_infer_vars` tried to look up these unregistered regions. This ensures all late-bound regions are properly registered in the universal regions map before they're needed during region substitution.
1 parent 3545698 commit 62ab2c2

File tree

4 files changed

+113
-19
lines changed

4 files changed

+113
-19
lines changed

compiler/rustc_borrowck/src/universal_regions.rs

Lines changed: 45 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -516,21 +516,53 @@ impl<'cx, 'tcx> UniversalRegionsBuilder<'cx, 'tcx> {
516516
// Converse of above, if this is a function/closure then the late-bound regions declared
517517
// on its signature are local.
518518
//
519-
// We manually loop over `bound_inputs_and_output` instead of using
520-
// `for_each_late_bound_region_in_item` as we may need to add the otherwise
521-
// implicit `ClosureEnv` region.
519+
// For closures/coroutines, we manually loop over `bound_inputs_and_output` instead of
520+
// using `for_each_late_bound_region_in_item` as we may need to add the otherwise
521+
// implicit `ClosureEnv` region. For regular functions, we need to use
522+
// `for_each_late_bound_region_in_item` to ensure we capture all late-bound regions,
523+
// including those that don't appear in the inputs/output (e.g., unused lifetime parameters).
522524
let bound_inputs_and_output = self.compute_inputs_and_output(&indices, defining_ty);
523-
for (idx, bound_var) in bound_inputs_and_output.bound_vars().iter().enumerate() {
524-
if let ty::BoundVariableKind::Region(kind) = bound_var {
525-
let kind = ty::LateParamRegionKind::from_bound(ty::BoundVar::from_usize(idx), kind);
526-
let r = ty::Region::new_late_param(self.infcx.tcx, self.mir_def.to_def_id(), kind);
527-
let region_vid = {
528-
let name = r.get_name_or_anon(self.infcx.tcx);
529-
self.infcx.next_nll_region_var(FR, || RegionCtxt::LateBound(name))
530-
};
525+
match defining_ty {
526+
DefiningTy::Closure(..)
527+
| DefiningTy::Coroutine(..)
528+
| DefiningTy::CoroutineClosure(..) => {
529+
// For closures/coroutines, iterate over bound_vars to include implicit regions.
530+
for (idx, bound_var) in bound_inputs_and_output.bound_vars().iter().enumerate() {
531+
if let ty::BoundVariableKind::Region(kind) = bound_var {
532+
let kind = ty::LateParamRegionKind::from_bound(
533+
ty::BoundVar::from_usize(idx),
534+
kind,
535+
);
536+
let r = ty::Region::new_late_param(
537+
self.infcx.tcx,
538+
self.mir_def.to_def_id(),
539+
kind,
540+
);
541+
let region_vid = {
542+
let name = r.get_name_or_anon(self.infcx.tcx);
543+
self.infcx.next_nll_region_var(FR, || RegionCtxt::LateBound(name))
544+
};
545+
546+
debug!(?region_vid);
547+
indices.insert_late_bound_region(r, region_vid.as_var());
548+
}
549+
}
550+
}
551+
DefiningTy::FnDef(..) => {
552+
// For functions, use for_each_late_bound_region_in_item to ensure we capture
553+
// all late-bound regions, including those that don't appear in inputs/output.
554+
for_each_late_bound_region_in_item(self.infcx.tcx, self.mir_def, |r| {
555+
let region_vid = {
556+
let name = r.get_name_or_anon(self.infcx.tcx);
557+
self.infcx.next_nll_region_var(FR, || RegionCtxt::LateBound(name))
558+
};
531559

532-
debug!(?region_vid);
533-
indices.insert_late_bound_region(r, region_vid.as_var());
560+
debug!(?region_vid);
561+
indices.insert_late_bound_region(r, region_vid.as_var());
562+
});
563+
}
564+
DefiningTy::Const(..) | DefiningTy::InlineConst(..) | DefiningTy::GlobalAsm(..) => {
565+
// These don't have late-bound regions.
534566
}
535567
}
536568
let inputs_and_output = self.infcx.replace_bound_regions_with_nll_infer_vars(

tests/crashes/135845.rs

Lines changed: 0 additions & 6 deletions
This file was deleted.
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
// Regression test for issue #135845
2+
// Ensure we don't ICE when a lifetime parameter from a function
3+
// is incorrectly used in an expression.
4+
5+
struct S<'a, T: ?Sized>(&'a T);
6+
7+
fn b<'a>() -> S<'static, _> {
8+
//~^ ERROR the placeholder `_` is not allowed within types on item signatures for return types
9+
S::<'a>(&0)
10+
}
11+
12+
fn static_to_a_to_static_through_ref_in_tuple<'a>(x: &'a u32) -> &'a _ {
13+
//~^ ERROR the placeholder `_` is not allowed within types on item signatures for return types
14+
let (ref y, _z): (&'a u32, u32) = (&22, 44);
15+
*y
16+
}
17+
18+
fn opt_str2<'a>(maybestr: &'a Option<String>) -> &'a _ {
19+
//~^ ERROR the placeholder `_` is not allowed within types on item signatures for return types
20+
match *maybestr {
21+
None => "(none)",
22+
Some(ref s) => {
23+
let s: &'a str = s;
24+
s
25+
}
26+
}
27+
}
28+
29+
fn main() {}
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
error[E0121]: the placeholder `_` is not allowed within types on item signatures for return types
2+
--> $DIR/late-bound-misuse-issue-135845.rs:7:26
3+
|
4+
LL | fn b<'a>() -> S<'static, _> {
5+
| ^ not allowed in type signatures
6+
|
7+
help: replace with the correct return type
8+
|
9+
LL - fn b<'a>() -> S<'static, _> {
10+
LL + fn b<'a>() -> S<'_, i32> {
11+
|
12+
13+
error[E0121]: the placeholder `_` is not allowed within types on item signatures for return types
14+
--> $DIR/late-bound-misuse-issue-135845.rs:12:70
15+
|
16+
LL | fn static_to_a_to_static_through_ref_in_tuple<'a>(x: &'a u32) -> &'a _ {
17+
| ^ not allowed in type signatures
18+
|
19+
help: replace with the correct return type
20+
|
21+
LL - fn static_to_a_to_static_through_ref_in_tuple<'a>(x: &'a u32) -> &'a _ {
22+
LL + fn static_to_a_to_static_through_ref_in_tuple<'a>(x: &'a u32) -> &u32 {
23+
|
24+
25+
error[E0121]: the placeholder `_` is not allowed within types on item signatures for return types
26+
--> $DIR/late-bound-misuse-issue-135845.rs:18:54
27+
|
28+
LL | fn opt_str2<'a>(maybestr: &'a Option<String>) -> &'a _ {
29+
| ^ not allowed in type signatures
30+
|
31+
help: replace with the correct return type
32+
|
33+
LL - fn opt_str2<'a>(maybestr: &'a Option<String>) -> &'a _ {
34+
LL + fn opt_str2<'a>(maybestr: &'a Option<String>) -> &str {
35+
|
36+
37+
error: aborting due to 3 previous errors
38+
39+
For more information about this error, try `rustc --explain E0121`.

0 commit comments

Comments
 (0)