From 62ab2c25bd786c75893596dfe19b83b163617942 Mon Sep 17 00:00:00 2001 From: Yuki Okushi Date: Mon, 13 Oct 2025 19:22:28 +0900 Subject: [PATCH] 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. --- .../rustc_borrowck/src/universal_regions.rs | 58 ++++++++++++++----- tests/crashes/135845.rs | 6 -- .../late-bound-misuse-issue-135845.rs | 29 ++++++++++ .../late-bound-misuse-issue-135845.stderr | 39 +++++++++++++ 4 files changed, 113 insertions(+), 19 deletions(-) delete mode 100644 tests/crashes/135845.rs create mode 100644 tests/ui/lifetimes/late-bound-misuse-issue-135845.rs create mode 100644 tests/ui/lifetimes/late-bound-misuse-issue-135845.stderr diff --git a/compiler/rustc_borrowck/src/universal_regions.rs b/compiler/rustc_borrowck/src/universal_regions.rs index 64a7b4084349d..9c91806ac6768 100644 --- a/compiler/rustc_borrowck/src/universal_regions.rs +++ b/compiler/rustc_borrowck/src/universal_regions.rs @@ -516,21 +516,53 @@ impl<'cx, 'tcx> UniversalRegionsBuilder<'cx, 'tcx> { // Converse of above, if this is a function/closure then the late-bound regions declared // on its signature are local. // - // We manually loop over `bound_inputs_and_output` instead of using - // `for_each_late_bound_region_in_item` as we may need to add the otherwise - // implicit `ClosureEnv` region. + // For closures/coroutines, we manually loop over `bound_inputs_and_output` instead of + // using `for_each_late_bound_region_in_item` as we may need to add the otherwise + // implicit `ClosureEnv` region. For regular functions, we need to use + // `for_each_late_bound_region_in_item` to ensure we capture all late-bound regions, + // including those that don't appear in the inputs/output (e.g., unused lifetime parameters). let bound_inputs_and_output = self.compute_inputs_and_output(&indices, defining_ty); - for (idx, bound_var) in bound_inputs_and_output.bound_vars().iter().enumerate() { - if let ty::BoundVariableKind::Region(kind) = bound_var { - let kind = ty::LateParamRegionKind::from_bound(ty::BoundVar::from_usize(idx), kind); - let r = ty::Region::new_late_param(self.infcx.tcx, self.mir_def.to_def_id(), kind); - let region_vid = { - let name = r.get_name_or_anon(self.infcx.tcx); - self.infcx.next_nll_region_var(FR, || RegionCtxt::LateBound(name)) - }; + match defining_ty { + DefiningTy::Closure(..) + | DefiningTy::Coroutine(..) + | DefiningTy::CoroutineClosure(..) => { + // For closures/coroutines, iterate over bound_vars to include implicit regions. + for (idx, bound_var) in bound_inputs_and_output.bound_vars().iter().enumerate() { + if let ty::BoundVariableKind::Region(kind) = bound_var { + let kind = ty::LateParamRegionKind::from_bound( + ty::BoundVar::from_usize(idx), + kind, + ); + let r = ty::Region::new_late_param( + self.infcx.tcx, + self.mir_def.to_def_id(), + kind, + ); + let region_vid = { + let name = r.get_name_or_anon(self.infcx.tcx); + self.infcx.next_nll_region_var(FR, || RegionCtxt::LateBound(name)) + }; + + debug!(?region_vid); + indices.insert_late_bound_region(r, region_vid.as_var()); + } + } + } + DefiningTy::FnDef(..) => { + // For functions, use for_each_late_bound_region_in_item to ensure we capture + // all late-bound regions, including those that don't appear in inputs/output. + for_each_late_bound_region_in_item(self.infcx.tcx, self.mir_def, |r| { + let region_vid = { + let name = r.get_name_or_anon(self.infcx.tcx); + self.infcx.next_nll_region_var(FR, || RegionCtxt::LateBound(name)) + }; - debug!(?region_vid); - indices.insert_late_bound_region(r, region_vid.as_var()); + debug!(?region_vid); + indices.insert_late_bound_region(r, region_vid.as_var()); + }); + } + DefiningTy::Const(..) | DefiningTy::InlineConst(..) | DefiningTy::GlobalAsm(..) => { + // These don't have late-bound regions. } } let inputs_and_output = self.infcx.replace_bound_regions_with_nll_infer_vars( diff --git a/tests/crashes/135845.rs b/tests/crashes/135845.rs deleted file mode 100644 index ed038d8a1f187..0000000000000 --- a/tests/crashes/135845.rs +++ /dev/null @@ -1,6 +0,0 @@ -//@ known-bug: #135845 -struct S<'a, T: ?Sized>(&'a T); - -fn b<'a>() -> S<'static, _> { - S::<'a>(&0) -} diff --git a/tests/ui/lifetimes/late-bound-misuse-issue-135845.rs b/tests/ui/lifetimes/late-bound-misuse-issue-135845.rs new file mode 100644 index 0000000000000..db6b78df6927c --- /dev/null +++ b/tests/ui/lifetimes/late-bound-misuse-issue-135845.rs @@ -0,0 +1,29 @@ +// Regression test for issue #135845 +// Ensure we don't ICE when a lifetime parameter from a function +// is incorrectly used in an expression. + +struct S<'a, T: ?Sized>(&'a T); + +fn b<'a>() -> S<'static, _> { + //~^ ERROR the placeholder `_` is not allowed within types on item signatures for return types + S::<'a>(&0) +} + +fn static_to_a_to_static_through_ref_in_tuple<'a>(x: &'a u32) -> &'a _ { + //~^ ERROR the placeholder `_` is not allowed within types on item signatures for return types + let (ref y, _z): (&'a u32, u32) = (&22, 44); + *y +} + +fn opt_str2<'a>(maybestr: &'a Option) -> &'a _ { + //~^ ERROR the placeholder `_` is not allowed within types on item signatures for return types + match *maybestr { + None => "(none)", + Some(ref s) => { + let s: &'a str = s; + s + } + } +} + +fn main() {} diff --git a/tests/ui/lifetimes/late-bound-misuse-issue-135845.stderr b/tests/ui/lifetimes/late-bound-misuse-issue-135845.stderr new file mode 100644 index 0000000000000..35e882f21bbed --- /dev/null +++ b/tests/ui/lifetimes/late-bound-misuse-issue-135845.stderr @@ -0,0 +1,39 @@ +error[E0121]: the placeholder `_` is not allowed within types on item signatures for return types + --> $DIR/late-bound-misuse-issue-135845.rs:7:26 + | +LL | fn b<'a>() -> S<'static, _> { + | ^ not allowed in type signatures + | +help: replace with the correct return type + | +LL - fn b<'a>() -> S<'static, _> { +LL + fn b<'a>() -> S<'_, i32> { + | + +error[E0121]: the placeholder `_` is not allowed within types on item signatures for return types + --> $DIR/late-bound-misuse-issue-135845.rs:12:70 + | +LL | fn static_to_a_to_static_through_ref_in_tuple<'a>(x: &'a u32) -> &'a _ { + | ^ not allowed in type signatures + | +help: replace with the correct return type + | +LL - fn static_to_a_to_static_through_ref_in_tuple<'a>(x: &'a u32) -> &'a _ { +LL + fn static_to_a_to_static_through_ref_in_tuple<'a>(x: &'a u32) -> &u32 { + | + +error[E0121]: the placeholder `_` is not allowed within types on item signatures for return types + --> $DIR/late-bound-misuse-issue-135845.rs:18:54 + | +LL | fn opt_str2<'a>(maybestr: &'a Option) -> &'a _ { + | ^ not allowed in type signatures + | +help: replace with the correct return type + | +LL - fn opt_str2<'a>(maybestr: &'a Option) -> &'a _ { +LL + fn opt_str2<'a>(maybestr: &'a Option) -> &str { + | + +error: aborting due to 3 previous errors + +For more information about this error, try `rustc --explain E0121`.