Skip to content

Commit

Permalink
Fix ICE when opaque captures a duplicated/invalid lifetime
Browse files Browse the repository at this point in the history
  • Loading branch information
compiler-errors committed Jan 1, 2025
1 parent 7f75bfa commit b7a4dcc
Show file tree
Hide file tree
Showing 5 changed files with 35 additions and 12 deletions.
4 changes: 2 additions & 2 deletions compiler/rustc_ast_lowering/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1845,11 +1845,11 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
GenericParamKind::Lifetime => {
// AST resolution emitted an error on those parameters, so we lower them using
// `ParamName::Error`.
let ident = self.lower_ident(param.ident);
let param_name =
if let Some(LifetimeRes::Error) = self.resolver.get_lifetime_res(param.id) {
ParamName::Error
ParamName::Error(ident)
} else {
let ident = self.lower_ident(param.ident);
ParamName::Plain(ident)
};
let kind =
Expand Down
16 changes: 9 additions & 7 deletions compiler/rustc_hir/src/hir.rs
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,13 @@ pub enum ParamName {
/// Some user-given name like `T` or `'x`.
Plain(Ident),

/// Indicates an illegal name was given and an error has been
/// reported (so we should squelch other derived errors).
///
/// Occurs when, e.g., `'_` is used in the wrong place, or a
/// lifetime name is duplicated.
Error(Ident),

/// Synthetic name generated when user elided a lifetime in an impl header.
///
/// E.g., the lifetimes in cases like these:
Expand All @@ -67,18 +74,13 @@ pub enum ParamName {
/// where `'f` is something like `Fresh(0)`. The indices are
/// unique per impl, but not necessarily continuous.
Fresh,

/// Indicates an illegal name was given and an error has been
/// reported (so we should squelch other derived errors). Occurs
/// when, e.g., `'_` is used in the wrong place.
Error,
}

impl ParamName {
pub fn ident(&self) -> Ident {
match *self {
ParamName::Plain(ident) => ident,
ParamName::Fresh | ParamName::Error => Ident::with_dummy_span(kw::UnderscoreLifetime),
ParamName::Plain(ident) | ParamName::Error(ident) => ident,
ParamName::Fresh => Ident::with_dummy_span(kw::UnderscoreLifetime),
}
}
}
Expand Down
4 changes: 2 additions & 2 deletions compiler/rustc_hir/src/intravisit.rs
Original file line number Diff line number Diff line change
Expand Up @@ -928,8 +928,8 @@ pub fn walk_generic_param<'v, V: Visitor<'v>>(
) -> V::Result {
try_visit!(visitor.visit_id(param.hir_id));
match param.name {
ParamName::Plain(ident) => try_visit!(visitor.visit_ident(ident)),
ParamName::Error | ParamName::Fresh => {}
ParamName::Plain(ident) | ParamName::Error(ident) => try_visit!(visitor.visit_ident(ident)),
ParamName::Fresh => {}
}
match param.kind {
GenericParamKind::Lifetime { .. } => {}
Expand Down
5 changes: 4 additions & 1 deletion compiler/rustc_hir_analysis/src/check/wfcheck.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2007,7 +2007,10 @@ fn check_variances_for_type_defn<'tcx>(
}

match hir_param.name {
hir::ParamName::Error => {}
hir::ParamName::Error(_) => {
// Don't report a bivariance error for a lifetime that isn't
// even valid to name.
}
_ => {
let has_explicit_bounds = explicitly_bounded_params.contains(&parameter);
report_bivariance(tcx, hir_param, has_explicit_bounds, item);
Expand Down
18 changes: 18 additions & 0 deletions tests/ui/impl-trait/captured-invalid-lifetime.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
// This uses edition 2024 for new lifetime capture rules.
//@ edition: 2024

// The problem here is that the presence of the opaque which captures all lifetimes in scope
// means that the duplicated `'a` (which I'll call the dupe) is considered to be *early-bound*
// since it shows up in the output but not the inputs. This is paired with the fact that we
// were previously setting the name of the dupe to `'_` in the generic param definition, which
// means that the identity args for the function were `['a#0, '_#1]` even though the lifetime
// for the dupe should've been `'a#1`. This difference in symbol meant that NLL couldn't
// actually match the lifetime against the identity lifeitmes, leading to an ICE.

struct Foo<'a>(&'a ());

impl<'a> Foo<'a> {
fn pass<'a>() -> impl Sized {}
}

fn main() {}

0 comments on commit b7a4dcc

Please sign in to comment.