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
This commit is contained in:
commit
44e794f8ab
5 changed files with 121 additions and 5 deletions
|
@ -147,3 +147,11 @@ hir_analysis_main_function_generic_parameters = `main` function is not allowed t
|
||||||
|
|
||||||
hir_analysis_variadic_function_compatible_convention = C-variadic function must have a compatible calling convention, like {$conventions}
|
hir_analysis_variadic_function_compatible_convention = C-variadic function must have a compatible calling convention, like {$conventions}
|
||||||
.label = C-variadic function must have a compatible calling convention
|
.label = C-variadic function must have a compatible calling convention
|
||||||
|
|
||||||
|
hir_analysis_cannot_capture_late_bound_ty_in_anon_const =
|
||||||
|
cannot capture late-bound type parameter in a constant
|
||||||
|
.label = parameter defined here
|
||||||
|
|
||||||
|
hir_analysis_cannot_capture_late_bound_const_in_anon_const =
|
||||||
|
cannot capture late-bound const parameter in a constant
|
||||||
|
.label = parameter defined here
|
||||||
|
|
|
@ -24,6 +24,8 @@ use rustc_span::symbol::{sym, Ident};
|
||||||
use rustc_span::Span;
|
use rustc_span::Span;
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
|
|
||||||
|
use crate::errors;
|
||||||
|
|
||||||
trait RegionExt {
|
trait RegionExt {
|
||||||
fn early(param: &GenericParam<'_>) -> (LocalDefId, ResolvedArg);
|
fn early(param: &GenericParam<'_>) -> (LocalDefId, ResolvedArg);
|
||||||
|
|
||||||
|
@ -161,6 +163,15 @@ enum Scope<'a> {
|
||||||
s: ScopeRef<'a>,
|
s: ScopeRef<'a>,
|
||||||
},
|
},
|
||||||
|
|
||||||
|
/// Disallows capturing non-lifetime binders from parent scopes.
|
||||||
|
///
|
||||||
|
/// This is necessary for something like `for<T> [(); { /* references T */ }]:`,
|
||||||
|
/// since we don't do something more correct like replacing any captured
|
||||||
|
/// late-bound vars with early-bound params in the const's own generics.
|
||||||
|
AnonConstBoundary {
|
||||||
|
s: ScopeRef<'a>,
|
||||||
|
},
|
||||||
|
|
||||||
Root {
|
Root {
|
||||||
opt_parent_item: Option<LocalDefId>,
|
opt_parent_item: Option<LocalDefId>,
|
||||||
},
|
},
|
||||||
|
@ -211,6 +222,7 @@ impl<'a> fmt::Debug for TruncatedScopeDebug<'a> {
|
||||||
.field("s", &"..")
|
.field("s", &"..")
|
||||||
.finish(),
|
.finish(),
|
||||||
Scope::TraitRefBoundary { s: _ } => f.debug_struct("TraitRefBoundary").finish(),
|
Scope::TraitRefBoundary { s: _ } => f.debug_struct("TraitRefBoundary").finish(),
|
||||||
|
Scope::AnonConstBoundary { s: _ } => f.debug_struct("AnonConstBoundary").finish(),
|
||||||
Scope::Root { opt_parent_item } => {
|
Scope::Root { opt_parent_item } => {
|
||||||
f.debug_struct("Root").field("opt_parent_item", &opt_parent_item).finish()
|
f.debug_struct("Root").field("opt_parent_item", &opt_parent_item).finish()
|
||||||
}
|
}
|
||||||
|
@ -312,7 +324,9 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> {
|
||||||
break (vec![], BinderScopeType::Normal);
|
break (vec![], BinderScopeType::Normal);
|
||||||
}
|
}
|
||||||
|
|
||||||
Scope::Elision { s, .. } | Scope::ObjectLifetimeDefault { s, .. } => {
|
Scope::Elision { s, .. }
|
||||||
|
| Scope::ObjectLifetimeDefault { s, .. }
|
||||||
|
| Scope::AnonConstBoundary { s } => {
|
||||||
scope = s;
|
scope = s;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1029,6 +1043,12 @@ impl<'a, 'tcx> Visitor<'tcx> for BoundVarContext<'a, 'tcx> {
|
||||||
fn visit_poly_trait_ref(&mut self, trait_ref: &'tcx hir::PolyTraitRef<'tcx>) {
|
fn visit_poly_trait_ref(&mut self, trait_ref: &'tcx hir::PolyTraitRef<'tcx>) {
|
||||||
self.visit_poly_trait_ref_inner(trait_ref, NonLifetimeBinderAllowed::Allow);
|
self.visit_poly_trait_ref_inner(trait_ref, NonLifetimeBinderAllowed::Allow);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn visit_anon_const(&mut self, c: &'tcx hir::AnonConst) {
|
||||||
|
self.with(Scope::AnonConstBoundary { s: self.scope }, |this| {
|
||||||
|
intravisit::walk_anon_const(this, c);
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn object_lifetime_default(tcx: TyCtxt<'_>, param_def_id: DefId) -> ObjectLifetimeDefault {
|
fn object_lifetime_default(tcx: TyCtxt<'_>, param_def_id: DefId) -> ObjectLifetimeDefault {
|
||||||
|
@ -1275,7 +1295,8 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> {
|
||||||
Scope::Elision { s, .. }
|
Scope::Elision { s, .. }
|
||||||
| Scope::ObjectLifetimeDefault { s, .. }
|
| Scope::ObjectLifetimeDefault { s, .. }
|
||||||
| Scope::Supertrait { s, .. }
|
| Scope::Supertrait { s, .. }
|
||||||
| Scope::TraitRefBoundary { s, .. } => {
|
| Scope::TraitRefBoundary { s, .. }
|
||||||
|
| Scope::AnonConstBoundary { s } => {
|
||||||
scope = s;
|
scope = s;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1340,7 +1361,8 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> {
|
||||||
| Scope::Elision { s, .. }
|
| Scope::Elision { s, .. }
|
||||||
| Scope::ObjectLifetimeDefault { s, .. }
|
| Scope::ObjectLifetimeDefault { s, .. }
|
||||||
| Scope::Supertrait { s, .. }
|
| Scope::Supertrait { s, .. }
|
||||||
| Scope::TraitRefBoundary { s, .. } => {
|
| Scope::TraitRefBoundary { s, .. }
|
||||||
|
| Scope::AnonConstBoundary { s } => {
|
||||||
scope = s;
|
scope = s;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1359,6 +1381,7 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> {
|
||||||
// search.
|
// search.
|
||||||
let mut late_depth = 0;
|
let mut late_depth = 0;
|
||||||
let mut scope = self.scope;
|
let mut scope = self.scope;
|
||||||
|
let mut crossed_anon_const = false;
|
||||||
let result = loop {
|
let result = loop {
|
||||||
match *scope {
|
match *scope {
|
||||||
Scope::Body { s, .. } => {
|
Scope::Body { s, .. } => {
|
||||||
|
@ -1392,10 +1415,36 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> {
|
||||||
| Scope::TraitRefBoundary { s, .. } => {
|
| Scope::TraitRefBoundary { s, .. } => {
|
||||||
scope = s;
|
scope = s;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Scope::AnonConstBoundary { s } => {
|
||||||
|
crossed_anon_const = true;
|
||||||
|
scope = s;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
if let Some(def) = result {
|
if let Some(def) = result {
|
||||||
|
if let ResolvedArg::LateBound(..) = def && crossed_anon_const {
|
||||||
|
let use_span = self.tcx.hir().span(hir_id);
|
||||||
|
let def_span = self.tcx.def_span(param_def_id);
|
||||||
|
match self.tcx.def_kind(param_def_id) {
|
||||||
|
DefKind::ConstParam => {
|
||||||
|
self.tcx.sess.emit_err(errors::CannotCaptureLateBoundInAnonConst::Const {
|
||||||
|
use_span,
|
||||||
|
def_span,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
DefKind::TyParam => {
|
||||||
|
self.tcx.sess.emit_err(errors::CannotCaptureLateBoundInAnonConst::Type {
|
||||||
|
use_span,
|
||||||
|
def_span,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
_ => unreachable!(),
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
self.map.defs.insert(hir_id, def);
|
self.map.defs.insert(hir_id, def);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -1474,7 +1523,8 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> {
|
||||||
| Scope::Elision { s, .. }
|
| Scope::Elision { s, .. }
|
||||||
| Scope::ObjectLifetimeDefault { s, .. }
|
| Scope::ObjectLifetimeDefault { s, .. }
|
||||||
| Scope::Supertrait { s, .. }
|
| Scope::Supertrait { s, .. }
|
||||||
| Scope::TraitRefBoundary { s, .. } => {
|
| Scope::TraitRefBoundary { s, .. }
|
||||||
|
| Scope::AnonConstBoundary { s } => {
|
||||||
scope = s;
|
scope = s;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1710,7 +1760,9 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> {
|
||||||
|
|
||||||
Scope::ObjectLifetimeDefault { lifetime: Some(l), .. } => break l,
|
Scope::ObjectLifetimeDefault { lifetime: Some(l), .. } => break l,
|
||||||
|
|
||||||
Scope::Supertrait { s, .. } | Scope::TraitRefBoundary { s, .. } => {
|
Scope::Supertrait { s, .. }
|
||||||
|
| Scope::TraitRefBoundary { s, .. }
|
||||||
|
| Scope::AnonConstBoundary { s } => {
|
||||||
scope = s;
|
scope = s;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -381,3 +381,21 @@ pub(crate) struct VariadicFunctionCompatibleConvention<'a> {
|
||||||
pub span: Span,
|
pub span: Span,
|
||||||
pub conventions: &'a str,
|
pub conventions: &'a str,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Diagnostic)]
|
||||||
|
pub(crate) enum CannotCaptureLateBoundInAnonConst {
|
||||||
|
#[diag(hir_analysis_cannot_capture_late_bound_ty_in_anon_const)]
|
||||||
|
Type {
|
||||||
|
#[primary_span]
|
||||||
|
use_span: Span,
|
||||||
|
#[label]
|
||||||
|
def_span: Span,
|
||||||
|
},
|
||||||
|
#[diag(hir_analysis_cannot_capture_late_bound_const_in_anon_const)]
|
||||||
|
Const {
|
||||||
|
#[primary_span]
|
||||||
|
use_span: Span,
|
||||||
|
#[label]
|
||||||
|
def_span: Span,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,11 @@
|
||||||
|
#![feature(non_lifetime_binders, generic_const_exprs)]
|
||||||
|
//~^ WARN the feature `non_lifetime_binders` is incomplete
|
||||||
|
//~| WARN the feature `generic_const_exprs` is incomplete
|
||||||
|
|
||||||
|
fn foo() -> usize
|
||||||
|
where
|
||||||
|
for<T> [i32; { let _: T = todo!(); 0 }]:,
|
||||||
|
//~^ ERROR cannot capture late-bound type parameter in a constant
|
||||||
|
{}
|
||||||
|
|
||||||
|
fn main() {}
|
|
@ -0,0 +1,27 @@
|
||||||
|
warning: the feature `non_lifetime_binders` is incomplete and may not be safe to use and/or cause compiler crashes
|
||||||
|
--> $DIR/late-bound-in-anon-ct.rs:1:12
|
||||||
|
|
|
||||||
|
LL | #![feature(non_lifetime_binders, generic_const_exprs)]
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
|
||||||
|
= note: see issue #108185 <https://github.com/rust-lang/rust/issues/108185> for more information
|
||||||
|
= note: `#[warn(incomplete_features)]` on by default
|
||||||
|
|
||||||
|
warning: the feature `generic_const_exprs` is incomplete and may not be safe to use and/or cause compiler crashes
|
||||||
|
--> $DIR/late-bound-in-anon-ct.rs:1:34
|
||||||
|
|
|
||||||
|
LL | #![feature(non_lifetime_binders, generic_const_exprs)]
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
|
||||||
|
= note: see issue #76560 <https://github.com/rust-lang/rust/issues/76560> for more information
|
||||||
|
|
||||||
|
error: cannot capture late-bound type parameter in a constant
|
||||||
|
--> $DIR/late-bound-in-anon-ct.rs:7:27
|
||||||
|
|
|
||||||
|
LL | for<T> [i32; { let _: T = todo!(); 0 }]:,
|
||||||
|
| - ^
|
||||||
|
| |
|
||||||
|
| parameter defined here
|
||||||
|
|
||||||
|
error: aborting due to previous error; 2 warnings emitted
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue