Skip to content

Commit 44e794f

Browse files
authored
Rollup merge of #108553 - compiler-errors:non-lt-late-bound-in-anon-ct, r=petrochenkov
Deny capturing late-bound non-lifetime param in anon const Introduce a new AnonConstBoundary so we can detect when we capture a late-bound non-lifetime param with `non_lifetime_binders` enabled. In the future, we could technically do something like introduce an early-bound parameter on the anon const, and stick the late-bound param in its substs (kinda like how we turn late-bound lifetimes in opaques into early-bound ones). But for now, just deny it so we don't ICE. Fixes #108191
2 parents 4f49352 + cbf4d4e commit 44e794f

File tree

5 files changed

+121
-5
lines changed

5 files changed

+121
-5
lines changed

compiler/rustc_hir_analysis/locales/en-US.ftl

+8
Original file line numberDiff line numberDiff line change
@@ -147,3 +147,11 @@ hir_analysis_main_function_generic_parameters = `main` function is not allowed t
147147
148148
hir_analysis_variadic_function_compatible_convention = C-variadic function must have a compatible calling convention, like {$conventions}
149149
.label = C-variadic function must have a compatible calling convention
150+
151+
hir_analysis_cannot_capture_late_bound_ty_in_anon_const =
152+
cannot capture late-bound type parameter in a constant
153+
.label = parameter defined here
154+
155+
hir_analysis_cannot_capture_late_bound_const_in_anon_const =
156+
cannot capture late-bound const parameter in a constant
157+
.label = parameter defined here

compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs

+57-5
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,8 @@ use rustc_span::symbol::{sym, Ident};
2424
use rustc_span::Span;
2525
use std::fmt;
2626

27+
use crate::errors;
28+
2729
trait RegionExt {
2830
fn early(param: &GenericParam<'_>) -> (LocalDefId, ResolvedArg);
2931

@@ -161,6 +163,15 @@ enum Scope<'a> {
161163
s: ScopeRef<'a>,
162164
},
163165

166+
/// Disallows capturing non-lifetime binders from parent scopes.
167+
///
168+
/// This is necessary for something like `for<T> [(); { /* references T */ }]:`,
169+
/// since we don't do something more correct like replacing any captured
170+
/// late-bound vars with early-bound params in the const's own generics.
171+
AnonConstBoundary {
172+
s: ScopeRef<'a>,
173+
},
174+
164175
Root {
165176
opt_parent_item: Option<LocalDefId>,
166177
},
@@ -211,6 +222,7 @@ impl<'a> fmt::Debug for TruncatedScopeDebug<'a> {
211222
.field("s", &"..")
212223
.finish(),
213224
Scope::TraitRefBoundary { s: _ } => f.debug_struct("TraitRefBoundary").finish(),
225+
Scope::AnonConstBoundary { s: _ } => f.debug_struct("AnonConstBoundary").finish(),
214226
Scope::Root { opt_parent_item } => {
215227
f.debug_struct("Root").field("opt_parent_item", &opt_parent_item).finish()
216228
}
@@ -312,7 +324,9 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> {
312324
break (vec![], BinderScopeType::Normal);
313325
}
314326

315-
Scope::Elision { s, .. } | Scope::ObjectLifetimeDefault { s, .. } => {
327+
Scope::Elision { s, .. }
328+
| Scope::ObjectLifetimeDefault { s, .. }
329+
| Scope::AnonConstBoundary { s } => {
316330
scope = s;
317331
}
318332

@@ -1029,6 +1043,12 @@ impl<'a, 'tcx> Visitor<'tcx> for BoundVarContext<'a, 'tcx> {
10291043
fn visit_poly_trait_ref(&mut self, trait_ref: &'tcx hir::PolyTraitRef<'tcx>) {
10301044
self.visit_poly_trait_ref_inner(trait_ref, NonLifetimeBinderAllowed::Allow);
10311045
}
1046+
1047+
fn visit_anon_const(&mut self, c: &'tcx hir::AnonConst) {
1048+
self.with(Scope::AnonConstBoundary { s: self.scope }, |this| {
1049+
intravisit::walk_anon_const(this, c);
1050+
});
1051+
}
10321052
}
10331053

10341054
fn object_lifetime_default(tcx: TyCtxt<'_>, param_def_id: DefId) -> ObjectLifetimeDefault {
@@ -1275,7 +1295,8 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> {
12751295
Scope::Elision { s, .. }
12761296
| Scope::ObjectLifetimeDefault { s, .. }
12771297
| Scope::Supertrait { s, .. }
1278-
| Scope::TraitRefBoundary { s, .. } => {
1298+
| Scope::TraitRefBoundary { s, .. }
1299+
| Scope::AnonConstBoundary { s } => {
12791300
scope = s;
12801301
}
12811302
}
@@ -1340,7 +1361,8 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> {
13401361
| Scope::Elision { s, .. }
13411362
| Scope::ObjectLifetimeDefault { s, .. }
13421363
| Scope::Supertrait { s, .. }
1343-
| Scope::TraitRefBoundary { s, .. } => {
1364+
| Scope::TraitRefBoundary { s, .. }
1365+
| Scope::AnonConstBoundary { s } => {
13441366
scope = s;
13451367
}
13461368
}
@@ -1359,6 +1381,7 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> {
13591381
// search.
13601382
let mut late_depth = 0;
13611383
let mut scope = self.scope;
1384+
let mut crossed_anon_const = false;
13621385
let result = loop {
13631386
match *scope {
13641387
Scope::Body { s, .. } => {
@@ -1392,10 +1415,36 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> {
13921415
| Scope::TraitRefBoundary { s, .. } => {
13931416
scope = s;
13941417
}
1418+
1419+
Scope::AnonConstBoundary { s } => {
1420+
crossed_anon_const = true;
1421+
scope = s;
1422+
}
13951423
}
13961424
};
13971425

13981426
if let Some(def) = result {
1427+
if let ResolvedArg::LateBound(..) = def && crossed_anon_const {
1428+
let use_span = self.tcx.hir().span(hir_id);
1429+
let def_span = self.tcx.def_span(param_def_id);
1430+
match self.tcx.def_kind(param_def_id) {
1431+
DefKind::ConstParam => {
1432+
self.tcx.sess.emit_err(errors::CannotCaptureLateBoundInAnonConst::Const {
1433+
use_span,
1434+
def_span,
1435+
});
1436+
}
1437+
DefKind::TyParam => {
1438+
self.tcx.sess.emit_err(errors::CannotCaptureLateBoundInAnonConst::Type {
1439+
use_span,
1440+
def_span,
1441+
});
1442+
}
1443+
_ => unreachable!(),
1444+
}
1445+
return;
1446+
}
1447+
13991448
self.map.defs.insert(hir_id, def);
14001449
return;
14011450
}
@@ -1474,7 +1523,8 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> {
14741523
| Scope::Elision { s, .. }
14751524
| Scope::ObjectLifetimeDefault { s, .. }
14761525
| Scope::Supertrait { s, .. }
1477-
| Scope::TraitRefBoundary { s, .. } => {
1526+
| Scope::TraitRefBoundary { s, .. }
1527+
| Scope::AnonConstBoundary { s } => {
14781528
scope = s;
14791529
}
14801530
}
@@ -1710,7 +1760,9 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> {
17101760

17111761
Scope::ObjectLifetimeDefault { lifetime: Some(l), .. } => break l,
17121762

1713-
Scope::Supertrait { s, .. } | Scope::TraitRefBoundary { s, .. } => {
1763+
Scope::Supertrait { s, .. }
1764+
| Scope::TraitRefBoundary { s, .. }
1765+
| Scope::AnonConstBoundary { s } => {
17141766
scope = s;
17151767
}
17161768
}

compiler/rustc_hir_analysis/src/errors.rs

+18
Original file line numberDiff line numberDiff line change
@@ -381,3 +381,21 @@ pub(crate) struct VariadicFunctionCompatibleConvention<'a> {
381381
pub span: Span,
382382
pub conventions: &'a str,
383383
}
384+
385+
#[derive(Diagnostic)]
386+
pub(crate) enum CannotCaptureLateBoundInAnonConst {
387+
#[diag(hir_analysis_cannot_capture_late_bound_ty_in_anon_const)]
388+
Type {
389+
#[primary_span]
390+
use_span: Span,
391+
#[label]
392+
def_span: Span,
393+
},
394+
#[diag(hir_analysis_cannot_capture_late_bound_const_in_anon_const)]
395+
Const {
396+
#[primary_span]
397+
use_span: Span,
398+
#[label]
399+
def_span: Span,
400+
},
401+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
#![feature(non_lifetime_binders, generic_const_exprs)]
2+
//~^ WARN the feature `non_lifetime_binders` is incomplete
3+
//~| WARN the feature `generic_const_exprs` is incomplete
4+
5+
fn foo() -> usize
6+
where
7+
for<T> [i32; { let _: T = todo!(); 0 }]:,
8+
//~^ ERROR cannot capture late-bound type parameter in a constant
9+
{}
10+
11+
fn main() {}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
warning: the feature `non_lifetime_binders` is incomplete and may not be safe to use and/or cause compiler crashes
2+
--> $DIR/late-bound-in-anon-ct.rs:1:12
3+
|
4+
LL | #![feature(non_lifetime_binders, generic_const_exprs)]
5+
| ^^^^^^^^^^^^^^^^^^^^
6+
|
7+
= note: see issue #108185 <https://github.com/rust-lang/rust/issues/108185> for more information
8+
= note: `#[warn(incomplete_features)]` on by default
9+
10+
warning: the feature `generic_const_exprs` is incomplete and may not be safe to use and/or cause compiler crashes
11+
--> $DIR/late-bound-in-anon-ct.rs:1:34
12+
|
13+
LL | #![feature(non_lifetime_binders, generic_const_exprs)]
14+
| ^^^^^^^^^^^^^^^^^^^
15+
|
16+
= note: see issue #76560 <https://github.com/rust-lang/rust/issues/76560> for more information
17+
18+
error: cannot capture late-bound type parameter in a constant
19+
--> $DIR/late-bound-in-anon-ct.rs:7:27
20+
|
21+
LL | for<T> [i32; { let _: T = todo!(); 0 }]:,
22+
| - ^
23+
| |
24+
| parameter defined here
25+
26+
error: aborting due to previous error; 2 warnings emitted
27+

0 commit comments

Comments
 (0)