-
Notifications
You must be signed in to change notification settings - Fork 13.5k
Correctly deny late-bound lifetimes from parent in anon consts and TAITs #115486
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
Changes from 1 commit
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
- Loading branch information
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,23 +1,13 @@ | ||
// failure-status: 1 | ||
// known-bug: unknown | ||
// error-pattern:internal compiler error | ||
// normalize-stderr-test "internal compiler error.*" -> "" | ||
// normalize-stderr-test "DefId\([^)]*\)" -> "..." | ||
// normalize-stderr-test "\nerror: internal compiler error.*\n\n" -> "" | ||
// normalize-stderr-test "note:.*unexpectedly panicked.*\n\n" -> "" | ||
// normalize-stderr-test "note: we would appreciate a bug report.*\n\n" -> "" | ||
// normalize-stderr-test "note: compiler flags.*\n\n" -> "" | ||
// normalize-stderr-test "note: rustc.*running on.*\n\n" -> "" | ||
// normalize-stderr-test "thread.*panicked.*:\n.*\n" -> "" | ||
// normalize-stderr-test "stack backtrace:\n" -> "" | ||
// normalize-stderr-test "\s\d{1,}: .*\n" -> "" | ||
// normalize-stderr-test "\s at .*\n" -> "" | ||
// normalize-stderr-test ".*note: Some details.*\n" -> "" | ||
// normalize-stderr-test "\n[ ]*\n" -> "" | ||
// normalize-stderr-test "compiler/.*: projection" -> "projection" | ||
// normalize-stderr-test ".*omitted \d{1,} frame.*\n" -> "" | ||
// normalize-stderr-test "error: [\s\n]*query stack during panic:\n" -> "" | ||
// this should run-pass | ||
|
||
// If we want this to compile, then we'd need to do something like RPITs do, | ||
// where nested associated constants have early-bound versions of their captured | ||
// late-bound vars inserted into their generics. This gives us substitutable | ||
// lifetimes to actually use when borrow-checking the associated const, which is | ||
// lowered as a totally separate body from its parent. Since this doesn't exist, | ||
// so we should just error rather than resolving this late-bound var with no | ||
// binder to actually attach it to, or worse, as a free region that can't even be | ||
// substituted correctly, and ICEing. - @compiler-errors | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The purpose of this comment is to ramble a bit about a more general solution than what would be needed to fix just this test and its related test ( But, for the record, #79298 never really correctly supported referencing late-bound regions in anon consts that show up in general positions (i.e. other positions where the const wasn't just referencing a free region in the scope of a body), e.g.: // ICEs even on 1.51 after #79298
#![feature(const_generics)] // `generic_const_exprs` after it was renamed.
#![allow(incomplete_features)]
const fn inner<'a: 'a>() -> usize {
3
}
fn test<'a>() -> [u8; { inner::<'a>() }] {
[1, 2, 3]
}
fn main() {
test();
} or in other binders, like: trait Trait {
type Assoc;
}
fn test() {
let x: dyn for<'a> Trait<Assoc = [u8; { inner::<'a>() }]>;
} This isn't necessarily the only solution to fix this -- I guess we could (ab)use free regions to correctly borrowck consts that show up in the binders above, but it seems pretty obvious to me that the clearest and easiest way to do this is to just represent late-bound vars captured by nested consts as early-bound regions owned by those consts. |
||
|
||
#![feature(generic_const_exprs)] | ||
#![allow(incomplete_features)] | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,10 +1,20 @@ | ||
#0 [mir_borrowck] borrow-checking `test::{closure#0}::{constant#1}` | ||
#1 [mir_drops_elaborated_and_const_checked] elaborating drops for `test::{closure#0}::{constant#1}` | ||
#2 [mir_for_ctfe] caching mir of `test::{closure#0}::{constant#1}` for CTFE | ||
#3 [eval_to_allocation_raw] const-evaluating + checking `test::{closure#0}::{constant#1}` | ||
#4 [eval_to_allocation_raw] const-evaluating + checking `test::{closure#0}::{constant#1}` | ||
#5 [eval_to_valtree] evaluating type-level constant | ||
#6 [typeck] type-checking `test` | ||
#7 [analysis] running analysis passes on this crate | ||
end of query stack | ||
error: aborting due to previous error | ||
error: cannot capture late-bound lifetime in constant | ||
--> $DIR/in_closure.rs:24:29 | ||
| | ||
LL | fn test<'a>() { | ||
| -- lifetime defined here | ||
LL | let _ = || { | ||
LL | let _: [u8; inner::<'a>()]; | ||
| ^^ | ||
|
||
error: cannot capture late-bound lifetime in constant | ||
--> $DIR/in_closure.rs:25:29 | ||
| | ||
LL | fn test<'a>() { | ||
| -- lifetime defined here | ||
... | ||
LL | let _ = [0; inner::<'a>()]; | ||
| ^^ | ||
|
||
error: aborting due to 2 previous errors | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,12 +1,19 @@ | ||
error: query stack during panic: | ||
#0 [mir_borrowck] borrow-checking `test::{constant#1}` | ||
#1 [mir_drops_elaborated_and_const_checked] elaborating drops for `test::{constant#1}` | ||
#2 [mir_for_ctfe] caching mir of `test::{constant#1}` for CTFE | ||
#3 [eval_to_allocation_raw] const-evaluating + checking `test::{constant#1}` | ||
#4 [eval_to_allocation_raw] const-evaluating + checking `test::{constant#1}` | ||
#5 [eval_to_valtree] evaluating type-level constant | ||
#6 [typeck] type-checking `test` | ||
#7 [analysis] running analysis passes on this crate | ||
end of query stack | ||
error: aborting due to previous error | ||
error: cannot capture late-bound lifetime in constant | ||
--> $DIR/simple.rs:20:25 | ||
| | ||
LL | fn test<'a>() { | ||
| -- lifetime defined here | ||
LL | let _: [u8; inner::<'a>()]; | ||
| ^^ | ||
|
||
error: cannot capture late-bound lifetime in constant | ||
--> $DIR/simple.rs:21:25 | ||
| | ||
LL | fn test<'a>() { | ||
| -- lifetime defined here | ||
LL | let _: [u8; inner::<'a>()]; | ||
LL | let _ = [0; inner::<'a>()]; | ||
| ^^ | ||
|
||
error: aborting due to 2 previous errors | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
#![feature(generic_const_exprs)] | ||
//~^ WARN the feature `generic_const_exprs` is incomplete | ||
|
||
fn test<'a>( | ||
_: &'a (), | ||
) -> [(); { | ||
let x: &'a (); | ||
//~^ ERROR cannot capture late-bound lifetime in constant | ||
1 | ||
}] { | ||
} | ||
|
||
fn main() {} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Both this branch and the next (
if let Some(body_id) = outermost_body
) should only be executed for late-bound variables. Should they both be in anif let ResolvedArg::LateBound(_, _, param_def_id) = def
to make it clearer?For my curiosity, what would happen if we made lifetimes in anon-consts
ResolvedArg::Free
?There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
See my comment here #115486 (comment), I kinda went into it there -- this idea would, in fact, fix at least tests like
const-generics/late-bound-vars/in_closure.rs
andconst-generics/late-bound-vars/simple.rs
, and was how #79298 worked, afaict.It doesn't seem like a general solution, though, since when it comes to, e.g., a binder on a where clause like
where for<'a> [(); { /* const that uses 'a */ }]: ...
, it doesn't really make sense to useReFree
for that usage of'a
, since the late-bound region does not originate from the function's generics (and therefore thefn_sig
's binder).This also doesn't lead us towards a correct solution for handling things like
for<const C: usize> [(); C]: ...
, since there's no equivalent notion of a "free" type or const var (nor does it make sense, since they must be substitutable).