Skip to content

Commit 1ec2c13

Browse files
committed
Auto merge of rust-lang#95779 - cjgillot:ast-lifetimes-undeclared, r=petrochenkov
Report undeclared lifetimes during late resolution. First step in rust-lang#91557 We reuse the rib design of the current resolution framework. Specific `LifetimeRib` and `LifetimeRibKind` types are introduced. The most important variant is `LifetimeRibKind::Generics`, which happens each time we encounter something which may introduce generic lifetime parameters. It can be an item or a `for<...>` binder. The `LifetimeBinderKind` specifies how this rib behaves with respect to in-band lifetimes. r? `@petrochenkov`
2 parents af68f71 + e628df9 commit 1ec2c13

File tree

54 files changed

+1859
-782
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

54 files changed

+1859
-782
lines changed

compiler/rustc_ast/src/visit.rs

+9-10
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ pub enum FnCtxt {
3535
#[derive(Copy, Clone, Debug)]
3636
pub enum FnKind<'a> {
3737
/// E.g., `fn foo()`, `fn foo(&self)`, or `extern "Abi" fn foo()`.
38-
Fn(FnCtxt, Ident, &'a FnSig, &'a Visibility, Option<&'a Block>),
38+
Fn(FnCtxt, Ident, &'a FnSig, &'a Visibility, &'a Generics, Option<&'a Block>),
3939

4040
/// E.g., `|x, y| body`.
4141
Closure(&'a FnDecl, &'a Expr),
@@ -44,7 +44,7 @@ pub enum FnKind<'a> {
4444
impl<'a> FnKind<'a> {
4545
pub fn header(&self) -> Option<&'a FnHeader> {
4646
match *self {
47-
FnKind::Fn(_, _, sig, _, _) => Some(&sig.header),
47+
FnKind::Fn(_, _, sig, _, _, _) => Some(&sig.header),
4848
FnKind::Closure(_, _) => None,
4949
}
5050
}
@@ -58,7 +58,7 @@ impl<'a> FnKind<'a> {
5858

5959
pub fn decl(&self) -> &'a FnDecl {
6060
match self {
61-
FnKind::Fn(_, _, sig, _, _) => &sig.decl,
61+
FnKind::Fn(_, _, sig, _, _, _) => &sig.decl,
6262
FnKind::Closure(decl, _) => decl,
6363
}
6464
}
@@ -295,8 +295,8 @@ pub fn walk_item<'a, V: Visitor<'a>>(visitor: &mut V, item: &'a Item) {
295295
walk_list!(visitor, visit_expr, expr);
296296
}
297297
ItemKind::Fn(box Fn { defaultness: _, ref generics, ref sig, ref body }) => {
298-
visitor.visit_generics(generics);
299-
let kind = FnKind::Fn(FnCtxt::Free, item.ident, sig, &item.vis, body.as_deref());
298+
let kind =
299+
FnKind::Fn(FnCtxt::Free, item.ident, sig, &item.vis, generics, body.as_deref());
300300
visitor.visit_fn(kind, item.span, item.id)
301301
}
302302
ItemKind::Mod(_unsafety, ref mod_kind) => match mod_kind {
@@ -561,8 +561,7 @@ pub fn walk_foreign_item<'a, V: Visitor<'a>>(visitor: &mut V, item: &'a ForeignI
561561
walk_list!(visitor, visit_expr, expr);
562562
}
563563
ForeignItemKind::Fn(box Fn { defaultness: _, ref generics, ref sig, ref body }) => {
564-
visitor.visit_generics(generics);
565-
let kind = FnKind::Fn(FnCtxt::Foreign, ident, sig, vis, body.as_deref());
564+
let kind = FnKind::Fn(FnCtxt::Foreign, ident, sig, vis, generics, body.as_deref());
566565
visitor.visit_fn(kind, span, id);
567566
}
568567
ForeignItemKind::TyAlias(box TyAlias { generics, bounds, ty, .. }) => {
@@ -644,7 +643,8 @@ pub fn walk_fn_decl<'a, V: Visitor<'a>>(visitor: &mut V, function_declaration: &
644643

645644
pub fn walk_fn<'a, V: Visitor<'a>>(visitor: &mut V, kind: FnKind<'a>, _span: Span) {
646645
match kind {
647-
FnKind::Fn(_, _, sig, _, body) => {
646+
FnKind::Fn(_, _, sig, _, generics, body) => {
647+
visitor.visit_generics(generics);
648648
visitor.visit_fn_header(&sig.header);
649649
walk_fn_decl(visitor, &sig.decl);
650650
walk_list!(visitor, visit_block, body);
@@ -667,8 +667,7 @@ pub fn walk_assoc_item<'a, V: Visitor<'a>>(visitor: &mut V, item: &'a AssocItem,
667667
walk_list!(visitor, visit_expr, expr);
668668
}
669669
AssocItemKind::Fn(box Fn { defaultness: _, ref generics, ref sig, ref body }) => {
670-
visitor.visit_generics(generics);
671-
let kind = FnKind::Fn(FnCtxt::Assoc(ctxt), ident, sig, vis, body.as_deref());
670+
let kind = FnKind::Fn(FnCtxt::Assoc(ctxt), ident, sig, vis, generics, body.as_deref());
672671
visitor.visit_fn(kind, span, id);
673672
}
674673
AssocItemKind::TyAlias(box TyAlias { generics, bounds, ty, .. }) => {

compiler/rustc_ast_lowering/src/lib.rs

+14-28
Original file line numberDiff line numberDiff line change
@@ -484,7 +484,7 @@ enum ParenthesizedGenericArgs {
484484
/// an "elided" or "underscore" lifetime name. In the future, we probably want to move
485485
/// everything into HIR lowering.
486486
#[derive(Copy, Clone, Debug)]
487-
enum AnonymousLifetimeMode {
487+
pub enum AnonymousLifetimeMode {
488488
/// For **Modern** cases, create a new anonymous region parameter
489489
/// and reference that.
490490
///
@@ -1835,7 +1835,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
18351835
// Output lifetime like `'_`:
18361836
for (span, node_id) in lifetimes_to_define {
18371837
let param = this.fresh_lifetime_to_generic_param(span, node_id);
1838-
lifetime_params.push((span, hir::LifetimeName::Implicit(false)));
1838+
lifetime_params.push((span, hir::LifetimeName::Implicit));
18391839
generic_params.push(param);
18401840
}
18411841
let generic_params = this.arena.alloc_from_iter(generic_params);
@@ -2017,16 +2017,16 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
20172017
});
20182018
let param_name = match lt.name {
20192019
hir::LifetimeName::Param(param_name) => param_name,
2020-
hir::LifetimeName::Implicit(_)
2021-
| hir::LifetimeName::Underscore
2022-
| hir::LifetimeName::Static => hir::ParamName::Plain(lt.name.ident()),
2020+
hir::LifetimeName::Implicit | hir::LifetimeName::Underscore => {
2021+
hir::ParamName::Plain(lt.name.ident())
2022+
}
20232023
hir::LifetimeName::ImplicitObjectLifetimeDefault => {
20242024
self.sess.diagnostic().span_bug(
20252025
param.ident.span,
20262026
"object-lifetime-default should not occur here",
20272027
);
20282028
}
2029-
hir::LifetimeName::Error => ParamName::Error,
2029+
hir::LifetimeName::Static | hir::LifetimeName::Error => ParamName::Error,
20302030
};
20312031

20322032
let kind =
@@ -2397,27 +2397,14 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
23972397

23982398
AnonymousLifetimeMode::ReportError => self.new_error_lifetime(None, span),
23992399

2400-
AnonymousLifetimeMode::PassThrough => self.new_implicit_lifetime(span, false),
2400+
AnonymousLifetimeMode::PassThrough => self.new_implicit_lifetime(span),
24012401
}
24022402
}
24032403

24042404
/// Report an error on illegal use of `'_` or a `&T` with no explicit lifetime;
24052405
/// return an "error lifetime".
24062406
fn new_error_lifetime(&mut self, id: Option<NodeId>, span: Span) -> hir::Lifetime {
2407-
let (id, msg, label) = match id {
2408-
Some(id) => (id, "`'_` cannot be used here", "`'_` is a reserved lifetime name"),
2409-
2410-
None => (
2411-
self.resolver.next_node_id(),
2412-
"`&` without an explicit lifetime name cannot be used here",
2413-
"explicit lifetime name needed here",
2414-
),
2415-
};
2416-
2417-
let mut err = struct_span_err!(self.sess, span, E0637, "{}", msg,);
2418-
err.span_label(span, label);
2419-
err.emit();
2420-
2407+
let id = id.unwrap_or_else(|| self.resolver.next_node_id());
24212408
self.new_named_lifetime(id, span, hir::LifetimeName::Error)
24222409
}
24232410

@@ -2429,12 +2416,11 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
24292416
&'s mut self,
24302417
span: Span,
24312418
count: usize,
2432-
param_mode: ParamMode,
24332419
) -> impl Iterator<Item = hir::Lifetime> + Captures<'a> + Captures<'s> + Captures<'hir> {
2434-
(0..count).map(move |_| self.elided_path_lifetime(span, param_mode))
2420+
(0..count).map(move |_| self.elided_path_lifetime(span))
24352421
}
24362422

2437-
fn elided_path_lifetime(&mut self, span: Span, param_mode: ParamMode) -> hir::Lifetime {
2423+
fn elided_path_lifetime(&mut self, span: Span) -> hir::Lifetime {
24382424
match self.anonymous_lifetime_mode {
24392425
AnonymousLifetimeMode::CreateParameter => {
24402426
// We should have emitted E0726 when processing this path above
@@ -2450,7 +2436,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
24502436
// lifetime. Instead, we simply create an implicit lifetime, which will be checked
24512437
// later, at which point a suitable error will be emitted.
24522438
AnonymousLifetimeMode::PassThrough | AnonymousLifetimeMode::ReportError => {
2453-
self.new_implicit_lifetime(span, param_mode == ParamMode::Explicit)
2439+
self.new_implicit_lifetime(span)
24542440
}
24552441
}
24562442
}
@@ -2493,11 +2479,11 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
24932479
r
24942480
}
24952481

2496-
fn new_implicit_lifetime(&mut self, span: Span, missing: bool) -> hir::Lifetime {
2482+
fn new_implicit_lifetime(&mut self, span: Span) -> hir::Lifetime {
24972483
hir::Lifetime {
24982484
hir_id: self.next_id(),
24992485
span: self.lower_span(span),
2500-
name: hir::LifetimeName::Implicit(missing),
2486+
name: hir::LifetimeName::Implicit,
25012487
}
25022488
}
25032489
}
@@ -2600,7 +2586,7 @@ fn lifetimes_from_impl_trait_bounds(
26002586

26012587
fn visit_lifetime(&mut self, lifetime: &'v hir::Lifetime) {
26022588
let name = match lifetime.name {
2603-
hir::LifetimeName::Implicit(_) | hir::LifetimeName::Underscore => {
2589+
hir::LifetimeName::Implicit | hir::LifetimeName::Underscore => {
26042590
if self.collect_elided_lifetimes {
26052591
// Use `'_` for both implicit and underscore lifetimes in
26062592
// `type Foo<'_> = impl SomeTrait<'_>;`.

compiler/rustc_ast_lowering/src/path.rs

+4-35
Original file line numberDiff line numberDiff line change
@@ -290,47 +290,16 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
290290
generic_args.span.with_lo(generic_args.span.lo() + BytePos(1)).shrink_to_lo()
291291
};
292292
generic_args.args = self
293-
.elided_path_lifetimes(elided_lifetime_span, expected_lifetimes, param_mode)
293+
.elided_path_lifetimes(elided_lifetime_span, expected_lifetimes)
294294
.map(GenericArg::Lifetime)
295295
.chain(generic_args.args.into_iter())
296296
.collect();
297-
// In create-parameter mode we error here because we don't want to support
298-
// deprecated impl elision in new features like impl elision and `async fn`,
299-
// both of which work using the `CreateParameter` mode:
300-
//
301-
// impl Foo for std::cell::Ref<u32> // note lack of '_
302-
// async fn foo(_: std::cell::Ref<u32>) { ... }
303297
if let (ParamMode::Explicit, AnonymousLifetimeMode::CreateParameter) =
304298
(param_mode, self.anonymous_lifetime_mode)
305299
{
306-
let anon_lt_suggestion = vec!["'_"; expected_lifetimes].join(", ");
307-
let no_non_lt_args = generic_args.args.len() == expected_lifetimes;
308-
let no_bindings = generic_args.bindings.is_empty();
309-
let (incl_angl_brckt, suggestion) = if no_non_lt_args && no_bindings {
310-
// If there are no generic args, our suggestion can include the angle brackets.
311-
(true, format!("<{}>", anon_lt_suggestion))
312-
} else {
313-
// Otherwise we'll insert a `'_, ` right after the opening bracket.
314-
(false, format!("{}, ", anon_lt_suggestion))
315-
};
316-
let insertion_sp = elided_lifetime_span.shrink_to_hi();
317-
let mut err = struct_span_err!(
318-
self.sess,
319-
path_span,
320-
E0726,
321-
"implicit elided lifetime not allowed here"
322-
);
323-
rustc_errors::add_elided_lifetime_in_path_suggestion(
324-
&self.sess.source_map(),
325-
&mut err,
326-
expected_lifetimes,
327-
path_span,
328-
incl_angl_brckt,
329-
insertion_sp,
330-
suggestion,
331-
);
332-
err.note("assuming a `'static` lifetime...");
333-
err.emit();
300+
// Late resolver should have issued the error.
301+
self.sess
302+
.delay_span_bug(elided_lifetime_span, "implicit lifetime not allowed here");
334303
}
335304
}
336305

compiler/rustc_ast_passes/src/ast_validation.rs

+24-16
Original file line numberDiff line numberDiff line change
@@ -91,16 +91,18 @@ impl<'a> AstValidator<'a> {
9191
self.is_impl_trait_banned = old;
9292
}
9393

94-
fn with_tilde_const_allowed(&mut self, f: impl FnOnce(&mut Self)) {
95-
let old = mem::replace(&mut self.is_tilde_const_allowed, true);
94+
fn with_tilde_const(&mut self, allowed: bool, f: impl FnOnce(&mut Self)) {
95+
let old = mem::replace(&mut self.is_tilde_const_allowed, allowed);
9696
f(self);
9797
self.is_tilde_const_allowed = old;
9898
}
9999

100+
fn with_tilde_const_allowed(&mut self, f: impl FnOnce(&mut Self)) {
101+
self.with_tilde_const(true, f)
102+
}
103+
100104
fn with_banned_tilde_const(&mut self, f: impl FnOnce(&mut Self)) {
101-
let old = mem::replace(&mut self.is_tilde_const_allowed, false);
102-
f(self);
103-
self.is_tilde_const_allowed = old;
105+
self.with_tilde_const(false, f)
104106
}
105107

106108
fn with_let_management(
@@ -1202,12 +1204,8 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
12021204
}
12031205
self.visit_vis(&item.vis);
12041206
self.visit_ident(item.ident);
1205-
if let Const::Yes(_) = sig.header.constness {
1206-
self.with_tilde_const_allowed(|this| this.visit_generics(generics));
1207-
} else {
1208-
self.visit_generics(generics);
1209-
}
1210-
let kind = FnKind::Fn(FnCtxt::Free, item.ident, sig, &item.vis, body.as_deref());
1207+
let kind =
1208+
FnKind::Fn(FnCtxt::Free, item.ident, sig, &item.vis, generics, body.as_deref());
12111209
self.visit_fn(kind, item.span, item.id);
12121210
walk_list!(self, visit_attribute, &item.attrs);
12131211
return; // Avoid visiting again.
@@ -1555,13 +1553,14 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
15551553
FnSig { span: sig_span, header: FnHeader { ext: Extern::Implicit, .. }, .. },
15561554
_,
15571555
_,
1556+
_,
15581557
) = fk
15591558
{
15601559
self.maybe_lint_missing_abi(*sig_span, id);
15611560
}
15621561

15631562
// Functions without bodies cannot have patterns.
1564-
if let FnKind::Fn(ctxt, _, sig, _, None) = fk {
1563+
if let FnKind::Fn(ctxt, _, sig, _, _, None) = fk {
15651564
Self::check_decl_no_pat(&sig.decl, |span, ident, mut_ident| {
15661565
let (code, msg, label) = match ctxt {
15671566
FnCtxt::Foreign => (
@@ -1596,7 +1595,11 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
15961595
});
15971596
}
15981597

1599-
visit::walk_fn(self, fk, span);
1598+
let tilde_const_allowed =
1599+
matches!(fk.header(), Some(FnHeader { constness: Const::Yes(_), .. }))
1600+
|| matches!(fk.ctxt(), Some(FnCtxt::Assoc(_)));
1601+
1602+
self.with_tilde_const(tilde_const_allowed, |this| visit::walk_fn(this, fk, span));
16001603
}
16011604

16021605
fn visit_assoc_item(&mut self, item: &'a AssocItem, ctxt: AssocCtxt) {
@@ -1670,9 +1673,14 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
16701673
{
16711674
self.visit_vis(&item.vis);
16721675
self.visit_ident(item.ident);
1673-
self.with_tilde_const_allowed(|this| this.visit_generics(generics));
1674-
let kind =
1675-
FnKind::Fn(FnCtxt::Assoc(ctxt), item.ident, sig, &item.vis, body.as_deref());
1676+
let kind = FnKind::Fn(
1677+
FnCtxt::Assoc(ctxt),
1678+
item.ident,
1679+
sig,
1680+
&item.vis,
1681+
generics,
1682+
body.as_deref(),
1683+
);
16761684
self.visit_fn(kind, item.span, item.id);
16771685
}
16781686
_ => self

compiler/rustc_borrowck/src/diagnostics/region_name.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -575,7 +575,7 @@ impl<'tcx> MirBorrowckCtxt<'_, 'tcx> {
575575
Some(RegionNameHighlight::MatchedAdtAndSegment(lifetime_span))
576576
}
577577

578-
hir::LifetimeName::ImplicitObjectLifetimeDefault | hir::LifetimeName::Implicit(_) => {
578+
hir::LifetimeName::ImplicitObjectLifetimeDefault | hir::LifetimeName::Implicit => {
579579
// In this case, the user left off the lifetime; so
580580
// they wrote something like:
581581
//

compiler/rustc_errors/src/lib.rs

+10-28
Original file line numberDiff line numberDiff line change
@@ -1511,35 +1511,17 @@ pub fn add_elided_lifetime_in_path_suggestion(
15111511
path_span: Span,
15121512
incl_angl_brckt: bool,
15131513
insertion_span: Span,
1514-
anon_lts: String,
15151514
) {
1516-
let (replace_span, suggestion) = if incl_angl_brckt {
1517-
(insertion_span, anon_lts)
1518-
} else {
1519-
// When possible, prefer a suggestion that replaces the whole
1520-
// `Path<T>` expression with `Path<'_, T>`, rather than inserting `'_, `
1521-
// at a point (which makes for an ugly/confusing label)
1522-
if let Ok(snippet) = source_map.span_to_snippet(path_span) {
1523-
// But our spans can get out of whack due to macros; if the place we think
1524-
// we want to insert `'_` isn't even within the path expression's span, we
1525-
// should bail out of making any suggestion rather than panicking on a
1526-
// subtract-with-overflow or string-slice-out-out-bounds (!)
1527-
// FIXME: can we do better?
1528-
if insertion_span.lo().0 < path_span.lo().0 {
1529-
return;
1530-
}
1531-
let insertion_index = (insertion_span.lo().0 - path_span.lo().0) as usize;
1532-
if insertion_index > snippet.len() {
1533-
return;
1534-
}
1535-
let (before, after) = snippet.split_at(insertion_index);
1536-
(path_span, format!("{}{}{}", before, anon_lts, after))
1537-
} else {
1538-
(insertion_span, anon_lts)
1539-
}
1540-
};
1541-
diag.span_suggestion(
1542-
replace_span,
1515+
diag.span_label(path_span, format!("expected lifetime parameter{}", pluralize!(n)));
1516+
if source_map.span_to_snippet(insertion_span).is_err() {
1517+
// Do not try to suggest anything if generated by a proc-macro.
1518+
return;
1519+
}
1520+
let anon_lts = vec!["'_"; n].join(", ");
1521+
let suggestion =
1522+
if incl_angl_brckt { format!("<{}>", anon_lts) } else { format!("{}, ", anon_lts) };
1523+
diag.span_suggestion_verbose(
1524+
insertion_span.shrink_to_hi(),
15431525
&format!("indicate the anonymous lifetime{}", pluralize!(n)),
15441526
suggestion,
15451527
Applicability::MachineApplicable,

0 commit comments

Comments
 (0)