Skip to content

Commit 2d56d38

Browse files
committed
Auto merge of rust-lang#115486 - compiler-errors:dont-capture-late-pls, r=cjgillot
Correctly deny late-bound lifetimes from parent in anon consts and TAITs Reuse the `AnonConstBoundary` scope (introduced in rust-lang#108553, renamed in this PR to `LateBoundary`) to deny late-bound vars of *all* kinds (ty/const/lifetime) in anon consts and TAITs. Side-note, but I would like to consolidate this with the error reporting for RPITs (E0657): https://github.com/rust-lang/rust/blob/c4f25777a08cd64b710e8a9a6159e67cbb35e6f5/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs#L733-L754 but the semantics about what we're allowed to capture there are slightly different, so I'm leaving that untouched. Fixes rust-lang#115474
2 parents 0692db1 + f479a7a commit 2d56d38

22 files changed

+268
-150
lines changed

compiler/rustc_hir_analysis/messages.ftl

+8-4
Original file line numberDiff line numberDiff line change
@@ -21,12 +21,16 @@ hir_analysis_auto_deref_reached_recursion_limit = reached the recursion limit wh
2121
.label = deref recursion limit reached
2222
.help = consider increasing the recursion limit by adding a `#![recursion_limit = "{$suggested_limit}"]` attribute to your crate (`{$crate_name}`)
2323
24-
hir_analysis_cannot_capture_late_bound_const_in_anon_const =
25-
cannot capture late-bound const parameter in a constant
24+
hir_analysis_cannot_capture_late_bound_const =
25+
cannot capture late-bound const parameter in {$what}
2626
.label = parameter defined here
2727
28-
hir_analysis_cannot_capture_late_bound_ty_in_anon_const =
29-
cannot capture late-bound type parameter in a constant
28+
hir_analysis_cannot_capture_late_bound_lifetime =
29+
cannot capture late-bound lifetime in {$what}
30+
.label = lifetime defined here
31+
32+
hir_analysis_cannot_capture_late_bound_ty =
33+
cannot capture late-bound type parameter in {$what}
3034
.label = parameter defined here
3135
3236
hir_analysis_cast_thin_pointer_to_fat_pointer = cannot cast thin pointer `{$expr_ty}` to fat pointer `{$cast_ty}`

compiler/rustc_hir_analysis/src/astconv/mod.rs

+1-3
Original file line numberDiff line numberDiff line change
@@ -268,9 +268,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
268268
// (*) -- not late-bound, won't change
269269
}
270270

271-
Some(rbv::ResolvedArg::Error(_)) => {
272-
bug!("only ty/ct should resolve as ResolvedArg::Error")
273-
}
271+
Some(rbv::ResolvedArg::Error(guar)) => ty::Region::new_error(tcx, guar),
274272

275273
None => {
276274
self.re_infer(def, lifetime.ident.span).unwrap_or_else(|| {

compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs

+51-20
Original file line numberDiff line numberDiff line change
@@ -158,13 +158,14 @@ enum Scope<'a> {
158158
s: ScopeRef<'a>,
159159
},
160160

161-
/// Disallows capturing non-lifetime binders from parent scopes.
161+
/// Disallows capturing late-bound vars from parent scopes.
162162
///
163163
/// This is necessary for something like `for<T> [(); { /* references T */ }]:`,
164164
/// since we don't do something more correct like replacing any captured
165165
/// late-bound vars with early-bound params in the const's own generics.
166-
AnonConstBoundary {
166+
LateBoundary {
167167
s: ScopeRef<'a>,
168+
what: &'static str,
168169
},
169170

170171
Root {
@@ -216,7 +217,9 @@ impl<'a> fmt::Debug for TruncatedScopeDebug<'a> {
216217
.field("s", &"..")
217218
.finish(),
218219
Scope::TraitRefBoundary { s: _ } => f.debug_struct("TraitRefBoundary").finish(),
219-
Scope::AnonConstBoundary { s: _ } => f.debug_struct("AnonConstBoundary").finish(),
220+
Scope::LateBoundary { s: _, what } => {
221+
f.debug_struct("LateBoundary").field("what", what).finish()
222+
}
220223
Scope::Root { opt_parent_item } => {
221224
f.debug_struct("Root").field("opt_parent_item", &opt_parent_item).finish()
222225
}
@@ -318,7 +321,7 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> {
318321
break (vec![], BinderScopeType::Normal);
319322
}
320323

321-
Scope::ObjectLifetimeDefault { s, .. } | Scope::AnonConstBoundary { s } => {
324+
Scope::ObjectLifetimeDefault { s, .. } | Scope::LateBoundary { s, .. } => {
322325
scope = s;
323326
}
324327

@@ -697,9 +700,12 @@ impl<'a, 'tcx> Visitor<'tcx> for BoundVarContext<'a, 'tcx> {
697700
}) => {
698701
intravisit::walk_ty(self, ty);
699702

700-
// Elided lifetimes are not allowed in non-return
701-
// position impl Trait
702-
let scope = Scope::TraitRefBoundary { s: self.scope };
703+
// Elided lifetimes and late-bound lifetimes (from the parent)
704+
// are not allowed in non-return position impl Trait
705+
let scope = Scope::LateBoundary {
706+
s: &Scope::TraitRefBoundary { s: self.scope },
707+
what: "type alias impl trait",
708+
};
703709
self.with(scope, |this| intravisit::walk_item(this, opaque_ty));
704710

705711
return;
@@ -979,7 +985,7 @@ impl<'a, 'tcx> Visitor<'tcx> for BoundVarContext<'a, 'tcx> {
979985
}
980986

981987
fn visit_anon_const(&mut self, c: &'tcx hir::AnonConst) {
982-
self.with(Scope::AnonConstBoundary { s: self.scope }, |this| {
988+
self.with(Scope::LateBoundary { s: self.scope, what: "constant" }, |this| {
983989
intravisit::walk_anon_const(this, c);
984990
});
985991
}
@@ -1174,6 +1180,7 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> {
11741180
let mut late_depth = 0;
11751181
let mut scope = self.scope;
11761182
let mut outermost_body = None;
1183+
let mut crossed_late_boundary = None;
11771184
let result = loop {
11781185
match *scope {
11791186
Scope::Body { id, s } => {
@@ -1258,8 +1265,12 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> {
12581265

12591266
Scope::ObjectLifetimeDefault { s, .. }
12601267
| Scope::Supertrait { s, .. }
1261-
| Scope::TraitRefBoundary { s, .. }
1262-
| Scope::AnonConstBoundary { s } => {
1268+
| Scope::TraitRefBoundary { s, .. } => {
1269+
scope = s;
1270+
}
1271+
1272+
Scope::LateBoundary { s, what } => {
1273+
crossed_late_boundary = Some(what);
12631274
scope = s;
12641275
}
12651276
}
@@ -1268,6 +1279,22 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> {
12681279
if let Some(mut def) = result {
12691280
if let ResolvedArg::EarlyBound(..) = def {
12701281
// Do not free early-bound regions, only late-bound ones.
1282+
} else if let ResolvedArg::LateBound(_, _, param_def_id) = def
1283+
&& let Some(what) = crossed_late_boundary
1284+
{
1285+
let use_span = lifetime_ref.ident.span;
1286+
let def_span = self.tcx.def_span(param_def_id);
1287+
let guar = match self.tcx.def_kind(param_def_id) {
1288+
DefKind::LifetimeParam => {
1289+
self.tcx.sess.emit_err(errors::CannotCaptureLateBound::Lifetime {
1290+
use_span,
1291+
def_span,
1292+
what,
1293+
})
1294+
}
1295+
_ => unreachable!(),
1296+
};
1297+
def = ResolvedArg::Error(guar);
12711298
} else if let Some(body_id) = outermost_body {
12721299
let fn_id = self.tcx.hir().body_owner(body_id);
12731300
match self.tcx.hir().get(fn_id) {
@@ -1322,7 +1349,7 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> {
13221349
| Scope::ObjectLifetimeDefault { s, .. }
13231350
| Scope::Supertrait { s, .. }
13241351
| Scope::TraitRefBoundary { s, .. }
1325-
| Scope::AnonConstBoundary { s } => {
1352+
| Scope::LateBoundary { s, .. } => {
13261353
scope = s;
13271354
}
13281355
}
@@ -1341,7 +1368,7 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> {
13411368
// search.
13421369
let mut late_depth = 0;
13431370
let mut scope = self.scope;
1344-
let mut crossed_anon_const = false;
1371+
let mut crossed_late_boundary = None;
13451372

13461373
let result = loop {
13471374
match *scope {
@@ -1376,28 +1403,32 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> {
13761403
scope = s;
13771404
}
13781405

1379-
Scope::AnonConstBoundary { s } => {
1380-
crossed_anon_const = true;
1406+
Scope::LateBoundary { s, what } => {
1407+
crossed_late_boundary = Some(what);
13811408
scope = s;
13821409
}
13831410
}
13841411
};
13851412

13861413
if let Some(def) = result {
1387-
if let ResolvedArg::LateBound(..) = def && crossed_anon_const {
1414+
if let ResolvedArg::LateBound(..) = def
1415+
&& let Some(what) = crossed_late_boundary
1416+
{
13881417
let use_span = self.tcx.hir().span(hir_id);
13891418
let def_span = self.tcx.def_span(param_def_id);
13901419
let guar = match self.tcx.def_kind(param_def_id) {
13911420
DefKind::ConstParam => {
1392-
self.tcx.sess.emit_err(errors::CannotCaptureLateBoundInAnonConst::Const {
1421+
self.tcx.sess.emit_err(errors::CannotCaptureLateBound::Const {
13931422
use_span,
13941423
def_span,
1424+
what,
13951425
})
13961426
}
13971427
DefKind::TyParam => {
1398-
self.tcx.sess.emit_err(errors::CannotCaptureLateBoundInAnonConst::Type {
1428+
self.tcx.sess.emit_err(errors::CannotCaptureLateBound::Type {
13991429
use_span,
14001430
def_span,
1431+
what,
14011432
})
14021433
}
14031434
_ => unreachable!(),
@@ -1446,7 +1477,7 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> {
14461477
| Scope::ObjectLifetimeDefault { s, .. }
14471478
| Scope::Supertrait { s, .. }
14481479
| Scope::TraitRefBoundary { s, .. }
1449-
| Scope::AnonConstBoundary { s } => {
1480+
| Scope::LateBoundary { s, .. } => {
14501481
scope = s;
14511482
}
14521483
}
@@ -1526,7 +1557,7 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> {
15261557
| Scope::ObjectLifetimeDefault { s, .. }
15271558
| Scope::Supertrait { s, .. }
15281559
| Scope::TraitRefBoundary { s, .. }
1529-
| Scope::AnonConstBoundary { s } => {
1560+
| Scope::LateBoundary { s, .. } => {
15301561
scope = s;
15311562
}
15321563
}
@@ -1831,7 +1862,7 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> {
18311862

18321863
Scope::Supertrait { s, .. }
18331864
| Scope::TraitRefBoundary { s, .. }
1834-
| Scope::AnonConstBoundary { s } => {
1865+
| Scope::LateBoundary { s, .. } => {
18351866
scope = s;
18361867
}
18371868
}

compiler/rustc_hir_analysis/src/errors.rs

+13-3
Original file line numberDiff line numberDiff line change
@@ -430,20 +430,30 @@ pub(crate) struct VariadicFunctionCompatibleConvention<'a> {
430430
}
431431

432432
#[derive(Diagnostic)]
433-
pub(crate) enum CannotCaptureLateBoundInAnonConst {
434-
#[diag(hir_analysis_cannot_capture_late_bound_ty_in_anon_const)]
433+
pub(crate) enum CannotCaptureLateBound {
434+
#[diag(hir_analysis_cannot_capture_late_bound_ty)]
435435
Type {
436436
#[primary_span]
437437
use_span: Span,
438438
#[label]
439439
def_span: Span,
440+
what: &'static str,
440441
},
441-
#[diag(hir_analysis_cannot_capture_late_bound_const_in_anon_const)]
442+
#[diag(hir_analysis_cannot_capture_late_bound_const)]
442443
Const {
443444
#[primary_span]
444445
use_span: Span,
445446
#[label]
446447
def_span: Span,
448+
what: &'static str,
449+
},
450+
#[diag(hir_analysis_cannot_capture_late_bound_lifetime)]
451+
Lifetime {
452+
#[primary_span]
453+
use_span: Span,
454+
#[label]
455+
def_span: Span,
456+
what: &'static str,
447457
},
448458
}
449459

tests/ui/const-generics/late-bound-vars/in_closure.rs

+1-19
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,5 @@
1-
// failure-status: 1
21
// known-bug: unknown
3-
// error-pattern:internal compiler error
4-
// normalize-stderr-test "internal compiler error.*" -> ""
5-
// normalize-stderr-test "DefId\([^)]*\)" -> "..."
6-
// normalize-stderr-test "\nerror: internal compiler error.*\n\n" -> ""
7-
// normalize-stderr-test "note:.*unexpectedly panicked.*\n\n" -> ""
8-
// normalize-stderr-test "note: we would appreciate a bug report.*\n\n" -> ""
9-
// normalize-stderr-test "note: compiler flags.*\n\n" -> ""
10-
// normalize-stderr-test "note: rustc.*running on.*\n\n" -> ""
11-
// normalize-stderr-test "thread.*panicked.*:\n.*\n" -> ""
12-
// normalize-stderr-test "stack backtrace:\n" -> ""
13-
// normalize-stderr-test "\s\d{1,}: .*\n" -> ""
14-
// normalize-stderr-test "\s at .*\n" -> ""
15-
// normalize-stderr-test ".*note: Some details.*\n" -> ""
16-
// normalize-stderr-test "\n[ ]*\n" -> ""
17-
// normalize-stderr-test "compiler/.*: projection" -> "projection"
18-
// normalize-stderr-test ".*omitted \d{1,} frame.*\n" -> ""
19-
// normalize-stderr-test "error: [\s\n]*query stack during panic:\n" -> ""
20-
// this should run-pass
2+
// see comment on `tests/ui/const-generics/late-bound-vars/simple.rs`
213

224
#![feature(generic_const_exprs)]
235
#![allow(incomplete_features)]
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,20 @@
1-
#0 [mir_borrowck] borrow-checking `test::{closure#0}::{constant#1}`
2-
#1 [mir_drops_elaborated_and_const_checked] elaborating drops for `test::{closure#0}::{constant#1}`
3-
#2 [mir_for_ctfe] caching mir of `test::{closure#0}::{constant#1}` for CTFE
4-
#3 [eval_to_allocation_raw] const-evaluating + checking `test::{closure#0}::{constant#1}`
5-
#4 [eval_to_allocation_raw] const-evaluating + checking `test::{closure#0}::{constant#1}`
6-
#5 [eval_to_valtree] evaluating type-level constant
7-
#6 [typeck] type-checking `test`
8-
#7 [analysis] running analysis passes on this crate
9-
end of query stack
10-
error: aborting due to previous error
1+
error: cannot capture late-bound lifetime in constant
2+
--> $DIR/in_closure.rs:16:29
3+
|
4+
LL | fn test<'a>() {
5+
| -- lifetime defined here
6+
LL | let _ = || {
7+
LL | let _: [u8; inner::<'a>()];
8+
| ^^
9+
10+
error: cannot capture late-bound lifetime in constant
11+
--> $DIR/in_closure.rs:17:29
12+
|
13+
LL | fn test<'a>() {
14+
| -- lifetime defined here
15+
...
16+
LL | let _ = [0; inner::<'a>()];
17+
| ^^
18+
19+
error: aborting due to 2 previous errors
20+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
// known-bug: unknown
2+
// see comment on `tests/ui/const-generics/late-bound-vars/simple.rs`
3+
4+
#![feature(generic_const_exprs)]
5+
#![allow(incomplete_features)]
6+
7+
trait MyTrait<T> {}
8+
9+
fn bug<'a, T>() -> &'static dyn MyTrait<[(); { |x: &'a u32| { x }; 4 }]> {
10+
todo!()
11+
}
12+
13+
fn main() {}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
error: cannot capture late-bound lifetime in constant
2+
--> $DIR/late-bound-in-return-issue-77357.rs:9:53
3+
|
4+
LL | fn bug<'a, T>() -> &'static dyn MyTrait<[(); { |x: &'a u32| { x }; 4 }]> {
5+
| -- lifetime defined here ^^
6+
7+
error: aborting due to previous error
8+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
// known-bug: unknown
2+
// see comment on `tests/ui/const-generics/late-bound-vars/simple.rs`
3+
4+
#![feature(generic_const_exprs)]
5+
#![allow(incomplete_features)]
6+
7+
fn bug<'a>()
8+
where
9+
for<'b> [(); {
10+
let x: &'b ();
11+
0
12+
}]:
13+
{}
14+
15+
fn main() {}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
error: cannot capture late-bound lifetime in constant
2+
--> $DIR/late-bound-in-where-issue-83993.rs:10:17
3+
|
4+
LL | for<'b> [(); {
5+
| -- lifetime defined here
6+
LL | let x: &'b ();
7+
| ^^
8+
9+
error: aborting due to previous error
10+

tests/ui/const-generics/late-bound-vars/simple.rs

+9-18
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,13 @@
1-
// failure-status: 101
21
// known-bug: unknown
3-
// error-pattern:internal compiler error
4-
// normalize-stderr-test "internal compiler error.*" -> ""
5-
// normalize-stderr-test "DefId\([^)]*\)" -> "..."
6-
// normalize-stderr-test "\nerror: internal compiler error.*\n\n" -> ""
7-
// normalize-stderr-test "note:.*unexpectedly panicked.*\n\n" -> ""
8-
// normalize-stderr-test "note: we would appreciate a bug report.*\n\n" -> ""
9-
// normalize-stderr-test "note: compiler flags.*\n\n" -> ""
10-
// normalize-stderr-test "note: rustc.*running on.*\n\n" -> ""
11-
// normalize-stderr-test "thread.*panicked.*:\n.*\n" -> ""
12-
// normalize-stderr-test "stack backtrace:\n" -> ""
13-
// normalize-stderr-test "\s\d{1,}: .*\n" -> ""
14-
// normalize-stderr-test "\s at .*\n" -> ""
15-
// normalize-stderr-test ".*note: Some details.*\n" -> ""
16-
// normalize-stderr-test "\n\n[ ]*\n" -> ""
17-
// normalize-stderr-test "compiler/.*: projection" -> "projection"
18-
// normalize-stderr-test ".*omitted \d{1,} frame.*\n" -> ""
19-
// normalize-stderr-test "error: [\s\n]*query stack" -> "error: query stack"
2+
3+
// If we want this to compile, then we'd need to do something like RPITs do,
4+
// where nested associated constants have early-bound versions of their captured
5+
// late-bound vars inserted into their generics. This gives us substitutable
6+
// lifetimes to actually use when borrow-checking the associated const, which is
7+
// lowered as a totally separate body from its parent. Since this doesn't exist,
8+
// we should just error rather than resolving this late-bound var with no
9+
// binder to actually attach it to, or worse, as a free region that can't even be
10+
// substituted correctly, and ICEing. - @compiler-errors
2011

2112
#![feature(generic_const_exprs)]
2213
#![allow(incomplete_features)]

0 commit comments

Comments
 (0)