Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Deny capturing late-bound non-lifetime param in anon const #108553

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions compiler/rustc_hir_analysis/locales/en-US.ftl
Original file line number Diff line number Diff line change
Expand Up @@ -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}
.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
62 changes: 57 additions & 5 deletions compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@ use rustc_span::symbol::{sym, Ident};
use rustc_span::Span;
use std::fmt;

use crate::errors;

trait RegionExt {
fn early(param: &GenericParam<'_>) -> (LocalDefId, ResolvedArg);

Expand Down Expand Up @@ -161,6 +163,15 @@ enum Scope<'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 {
opt_parent_item: Option<LocalDefId>,
},
Expand Down Expand Up @@ -211,6 +222,7 @@ impl<'a> fmt::Debug for TruncatedScopeDebug<'a> {
.field("s", &"..")
.finish(),
Scope::TraitRefBoundary { s: _ } => f.debug_struct("TraitRefBoundary").finish(),
Scope::AnonConstBoundary { s: _ } => f.debug_struct("AnonConstBoundary").finish(),
Scope::Root { opt_parent_item } => {
f.debug_struct("Root").field("opt_parent_item", &opt_parent_item).finish()
}
Expand Down Expand Up @@ -312,7 +324,9 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> {
break (vec![], BinderScopeType::Normal);
}

Scope::Elision { s, .. } | Scope::ObjectLifetimeDefault { s, .. } => {
Scope::Elision { s, .. }
| Scope::ObjectLifetimeDefault { s, .. }
| Scope::AnonConstBoundary { s } => {
scope = s;
}

Expand Down Expand Up @@ -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>) {
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 {
Expand Down Expand Up @@ -1267,7 +1287,8 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> {
Scope::Elision { s, .. }
| Scope::ObjectLifetimeDefault { s, .. }
| Scope::Supertrait { s, .. }
| Scope::TraitRefBoundary { s, .. } => {
| Scope::TraitRefBoundary { s, .. }
| Scope::AnonConstBoundary { s } => {
scope = s;
}
}
Expand Down Expand Up @@ -1332,7 +1353,8 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> {
| Scope::Elision { s, .. }
| Scope::ObjectLifetimeDefault { s, .. }
| Scope::Supertrait { s, .. }
| Scope::TraitRefBoundary { s, .. } => {
| Scope::TraitRefBoundary { s, .. }
| Scope::AnonConstBoundary { s } => {
scope = s;
}
}
Expand All @@ -1351,6 +1373,7 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> {
// search.
let mut late_depth = 0;
let mut scope = self.scope;
let mut crossed_anon_const = false;
let result = loop {
match *scope {
Scope::Body { s, .. } => {
Expand Down Expand Up @@ -1384,10 +1407,36 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> {
| Scope::TraitRefBoundary { s, .. } => {
scope = s;
}

Scope::AnonConstBoundary { s } => {
crossed_anon_const = true;
scope = s;
}
}
};

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);
return;
}
Expand Down Expand Up @@ -1465,7 +1514,8 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> {
| Scope::Elision { s, .. }
| Scope::ObjectLifetimeDefault { s, .. }
| Scope::Supertrait { s, .. }
| Scope::TraitRefBoundary { s, .. } => {
| Scope::TraitRefBoundary { s, .. }
| Scope::AnonConstBoundary { s } => {
scope = s;
}
}
Expand Down Expand Up @@ -1701,7 +1751,9 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> {

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

Scope::Supertrait { s, .. } | Scope::TraitRefBoundary { s, .. } => {
Scope::Supertrait { s, .. }
| Scope::TraitRefBoundary { s, .. }
| Scope::AnonConstBoundary { s } => {
scope = s;
}
}
Expand Down
18 changes: 18 additions & 0 deletions compiler/rustc_hir_analysis/src/errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -381,3 +381,21 @@ pub(crate) struct VariadicFunctionCompatibleConvention<'a> {
pub span: Span,
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,
},
}
11 changes: 11 additions & 0 deletions tests/ui/traits/non_lifetime_binders/late-bound-in-anon-ct.rs
Original file line number Diff line number Diff line change
@@ -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() {}
27 changes: 27 additions & 0 deletions tests/ui/traits/non_lifetime_binders/late-bound-in-anon-ct.stderr
Original file line number Diff line number Diff line change
@@ -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