Skip to content

Commit b7a4dcc

Browse files
Fix ICE when opaque captures a duplicated/invalid lifetime
1 parent 7f75bfa commit b7a4dcc

File tree

5 files changed

+35
-12
lines changed

5 files changed

+35
-12
lines changed

compiler/rustc_ast_lowering/src/lib.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -1845,11 +1845,11 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
18451845
GenericParamKind::Lifetime => {
18461846
// AST resolution emitted an error on those parameters, so we lower them using
18471847
// `ParamName::Error`.
1848+
let ident = self.lower_ident(param.ident);
18481849
let param_name =
18491850
if let Some(LifetimeRes::Error) = self.resolver.get_lifetime_res(param.id) {
1850-
ParamName::Error
1851+
ParamName::Error(ident)
18511852
} else {
1852-
let ident = self.lower_ident(param.ident);
18531853
ParamName::Plain(ident)
18541854
};
18551855
let kind =

compiler/rustc_hir/src/hir.rs

+9-7
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,13 @@ pub enum ParamName {
5252
/// Some user-given name like `T` or `'x`.
5353
Plain(Ident),
5454

55+
/// Indicates an illegal name was given and an error has been
56+
/// reported (so we should squelch other derived errors).
57+
///
58+
/// Occurs when, e.g., `'_` is used in the wrong place, or a
59+
/// lifetime name is duplicated.
60+
Error(Ident),
61+
5562
/// Synthetic name generated when user elided a lifetime in an impl header.
5663
///
5764
/// E.g., the lifetimes in cases like these:
@@ -67,18 +74,13 @@ pub enum ParamName {
6774
/// where `'f` is something like `Fresh(0)`. The indices are
6875
/// unique per impl, but not necessarily continuous.
6976
Fresh,
70-
71-
/// Indicates an illegal name was given and an error has been
72-
/// reported (so we should squelch other derived errors). Occurs
73-
/// when, e.g., `'_` is used in the wrong place.
74-
Error,
7577
}
7678

7779
impl ParamName {
7880
pub fn ident(&self) -> Ident {
7981
match *self {
80-
ParamName::Plain(ident) => ident,
81-
ParamName::Fresh | ParamName::Error => Ident::with_dummy_span(kw::UnderscoreLifetime),
82+
ParamName::Plain(ident) | ParamName::Error(ident) => ident,
83+
ParamName::Fresh => Ident::with_dummy_span(kw::UnderscoreLifetime),
8284
}
8385
}
8486
}

compiler/rustc_hir/src/intravisit.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -928,8 +928,8 @@ pub fn walk_generic_param<'v, V: Visitor<'v>>(
928928
) -> V::Result {
929929
try_visit!(visitor.visit_id(param.hir_id));
930930
match param.name {
931-
ParamName::Plain(ident) => try_visit!(visitor.visit_ident(ident)),
932-
ParamName::Error | ParamName::Fresh => {}
931+
ParamName::Plain(ident) | ParamName::Error(ident) => try_visit!(visitor.visit_ident(ident)),
932+
ParamName::Fresh => {}
933933
}
934934
match param.kind {
935935
GenericParamKind::Lifetime { .. } => {}

compiler/rustc_hir_analysis/src/check/wfcheck.rs

+4-1
Original file line numberDiff line numberDiff line change
@@ -2007,7 +2007,10 @@ fn check_variances_for_type_defn<'tcx>(
20072007
}
20082008

20092009
match hir_param.name {
2010-
hir::ParamName::Error => {}
2010+
hir::ParamName::Error(_) => {
2011+
// Don't report a bivariance error for a lifetime that isn't
2012+
// even valid to name.
2013+
}
20112014
_ => {
20122015
let has_explicit_bounds = explicitly_bounded_params.contains(&parameter);
20132016
report_bivariance(tcx, hir_param, has_explicit_bounds, item);
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
// This uses edition 2024 for new lifetime capture rules.
2+
//@ edition: 2024
3+
4+
// The problem here is that the presence of the opaque which captures all lifetimes in scope
5+
// means that the duplicated `'a` (which I'll call the dupe) is considered to be *early-bound*
6+
// since it shows up in the output but not the inputs. This is paired with the fact that we
7+
// were previously setting the name of the dupe to `'_` in the generic param definition, which
8+
// means that the identity args for the function were `['a#0, '_#1]` even though the lifetime
9+
// for the dupe should've been `'a#1`. This difference in symbol meant that NLL couldn't
10+
// actually match the lifetime against the identity lifeitmes, leading to an ICE.
11+
12+
struct Foo<'a>(&'a ());
13+
14+
impl<'a> Foo<'a> {
15+
fn pass<'a>() -> impl Sized {}
16+
}
17+
18+
fn main() {}

0 commit comments

Comments
 (0)