Skip to content

Commit f91adbd

Browse files
committed
Report undeclared lifetimes on AST.
1 parent ee1d5fe commit f91adbd

File tree

3 files changed

+146
-83
lines changed

3 files changed

+146
-83
lines changed

compiler/rustc_resolve/src/late.rs

Lines changed: 65 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -189,7 +189,7 @@ impl<'a, R> Rib<'a, R> {
189189
#[derive(Copy, Clone, Debug)]
190190
enum LifetimeRibKind {
191191
/// This rib declares generic parameters.
192-
Generics { parent: NodeId, kind: LifetimeBinderKind },
192+
Generics { parent: NodeId, span: Span, kind: LifetimeBinderKind },
193193

194194
/// We passed through a `macro_rules!` statement
195195
MacroDefinition(DefId),
@@ -228,6 +228,18 @@ enum LifetimeBinderKind {
228228
}
229229

230230
impl LifetimeBinderKind {
231+
fn descr(self) -> &'static str {
232+
use LifetimeBinderKind::*;
233+
match self {
234+
BareFnType => "type",
235+
PolyTrait => "bound",
236+
WhereBound => "bound",
237+
Item => "item",
238+
ImplBlock => "impl block",
239+
Function => "function",
240+
}
241+
}
242+
231243
fn allow_in_band(self) -> bool {
232244
use LifetimeBinderKind::*;
233245
match self {
@@ -570,12 +582,18 @@ impl<'a: 'ast, 'ast> Visitor<'ast> for LateResolutionVisitor<'a, '_, 'ast> {
570582
self.diagnostic_metadata.current_trait_object = Some(&bounds[..]);
571583
}
572584
TyKind::BareFn(ref bare_fn) => {
585+
let span = if let Some(param) = bare_fn.generic_params.first() {
586+
param.ident.span
587+
} else {
588+
ty.span.shrink_to_lo()
589+
};
573590
self.with_generic_param_rib(
574591
&bare_fn.generic_params,
575592
NormalRibKind,
576593
LifetimeRibKind::Generics {
577594
parent: ty.id,
578595
kind: LifetimeBinderKind::BareFnType,
596+
span,
579597
},
580598
|this| {
581599
this.with_lifetime_rib(
@@ -596,12 +614,15 @@ impl<'a: 'ast, 'ast> Visitor<'ast> for LateResolutionVisitor<'a, '_, 'ast> {
596614
self.diagnostic_metadata.current_trait_object = prev;
597615
}
598616
fn visit_poly_trait_ref(&mut self, tref: &'ast PolyTraitRef, _: &'ast TraitBoundModifier) {
617+
let span =
618+
if tref.bound_generic_params.is_empty() { tref.span.shrink_to_lo() } else { tref.span };
599619
self.with_generic_param_rib(
600620
&tref.bound_generic_params,
601621
NormalRibKind,
602622
LifetimeRibKind::Generics {
603623
parent: tref.trait_ref.ref_id,
604624
kind: LifetimeBinderKind::PolyTrait,
625+
span,
605626
},
606627
|this| {
607628
this.visit_generic_param_vec(&tref.bound_generic_params, false);
@@ -625,6 +646,7 @@ impl<'a: 'ast, 'ast> Visitor<'ast> for LateResolutionVisitor<'a, '_, 'ast> {
625646
LifetimeRibKind::Generics {
626647
parent: foreign_item.id,
627648
kind: LifetimeBinderKind::Item,
649+
span: generics.span,
628650
},
629651
|this| {
630652
visit::walk_foreign_item(this, foreign_item);
@@ -640,6 +662,7 @@ impl<'a: 'ast, 'ast> Visitor<'ast> for LateResolutionVisitor<'a, '_, 'ast> {
640662
LifetimeRibKind::Generics {
641663
parent: foreign_item.id,
642664
kind: LifetimeBinderKind::Function,
665+
span: generics.span,
643666
},
644667
|this| {
645668
visit::walk_foreign_item(this, foreign_item);
@@ -822,15 +845,26 @@ impl<'a: 'ast, 'ast> Visitor<'ast> for LateResolutionVisitor<'a, '_, 'ast> {
822845
ref bounded_ty,
823846
ref bounds,
824847
ref bound_generic_params,
848+
span: predicate_span,
825849
..
826850
}) = p
827851
{
852+
let span = if let Some(span) =
853+
bound_generic_params.iter().rev().find_map(|param| match param.kind {
854+
GenericParamKind::Lifetime => Some(param.ident.span),
855+
_ => None,
856+
}) {
857+
span.shrink_to_hi()
858+
} else {
859+
predicate_span.shrink_to_lo()
860+
};
828861
this.with_generic_param_rib(
829862
&bound_generic_params,
830863
NormalRibKind,
831864
LifetimeRibKind::Generics {
832865
parent: bounded_ty.id,
833866
kind: LifetimeBinderKind::WhereBound,
867+
span,
834868
},
835869
|this| {
836870
this.visit_generic_param_vec(&bound_generic_params, false);
@@ -1145,6 +1179,7 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
11451179
}
11461180
}
11471181

1182+
self.emit_undeclared_lifetime_error(lifetime);
11481183
self.r.lifetimes_res_map.insert(lifetime.id, LifetimeRes::Error);
11491184
}
11501185

@@ -1385,7 +1420,11 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
13851420
this.with_generic_param_rib(
13861421
&generics.params,
13871422
ItemRibKind(HasGenericParams::Yes),
1388-
LifetimeRibKind::Generics { parent: item.id, kind: LifetimeBinderKind::Item },
1423+
LifetimeRibKind::Generics {
1424+
parent: item.id,
1425+
kind: LifetimeBinderKind::Item,
1426+
span: generics.span,
1427+
},
13891428
|this| {
13901429
let item_def_id = this.r.local_def_id(item.id).to_def_id();
13911430
this.with_self_rib(Res::SelfTy(None, Some((item_def_id, false))), |this| {
@@ -1451,7 +1490,11 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
14511490
self.with_generic_param_rib(
14521491
&generics.params,
14531492
ItemRibKind(HasGenericParams::Yes),
1454-
LifetimeRibKind::Generics { parent: item.id, kind: LifetimeBinderKind::Item },
1493+
LifetimeRibKind::Generics {
1494+
parent: item.id,
1495+
kind: LifetimeBinderKind::Item,
1496+
span: generics.span,
1497+
},
14551498
|this| visit::walk_item(this, item),
14561499
);
14571500
}
@@ -1463,6 +1506,7 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
14631506
LifetimeRibKind::Generics {
14641507
parent: item.id,
14651508
kind: LifetimeBinderKind::Function,
1509+
span: generics.span,
14661510
},
14671511
|this| visit::walk_item(this, item),
14681512
);
@@ -1487,7 +1531,11 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
14871531
self.with_generic_param_rib(
14881532
&generics.params,
14891533
ItemRibKind(HasGenericParams::Yes),
1490-
LifetimeRibKind::Generics { parent: item.id, kind: LifetimeBinderKind::Item },
1534+
LifetimeRibKind::Generics {
1535+
parent: item.id,
1536+
kind: LifetimeBinderKind::Item,
1537+
span: generics.span,
1538+
},
14911539
|this| {
14921540
let local_def_id = this.r.local_def_id(item.id).to_def_id();
14931541
this.with_self_rib(Res::SelfTy(Some(local_def_id), None), |this| {
@@ -1502,7 +1550,11 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
15021550
this.with_generic_param_rib(
15031551
&generics.params,
15041552
AssocItemRibKind,
1505-
LifetimeRibKind::Generics { parent: item.id, kind },
1553+
LifetimeRibKind::Generics {
1554+
parent: item.id,
1555+
span: generics.span,
1556+
kind,
1557+
},
15061558
|this| visit::walk_assoc_item(this, item, AssocCtxt::Trait),
15071559
);
15081560
};
@@ -1562,7 +1614,11 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
15621614
self.with_generic_param_rib(
15631615
&generics.params,
15641616
ItemRibKind(HasGenericParams::Yes),
1565-
LifetimeRibKind::Generics { parent: item.id, kind: LifetimeBinderKind::Item },
1617+
LifetimeRibKind::Generics {
1618+
parent: item.id,
1619+
kind: LifetimeBinderKind::Item,
1620+
span: generics.span,
1621+
},
15661622
|this| {
15671623
let local_def_id = this.r.local_def_id(item.id).to_def_id();
15681624
this.with_self_rib(Res::SelfTy(Some(local_def_id), None), |this| {
@@ -1878,7 +1934,7 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
18781934
// method, it will not be considered an in-band
18791935
// lifetime to be added, but rather a reference to a
18801936
// parent lifetime.
1881-
self.with_generic_param_rib(&generics.params, ItemRibKind(HasGenericParams::Yes), LifetimeRibKind::Generics { parent: item_id, kind: LifetimeBinderKind::ImplBlock }, |this| {
1937+
self.with_generic_param_rib(&generics.params, ItemRibKind(HasGenericParams::Yes), LifetimeRibKind::Generics { span: generics.span, parent: item_id, kind: LifetimeBinderKind::ImplBlock }, |this| {
18821938
// Dummy self type for better errors if `Self` is used in the trait path.
18831939
this.with_self_rib(Res::SelfTy(None, None), |this| {
18841940
// Resolve the trait reference, if necessary.
@@ -1950,7 +2006,7 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
19502006
this.with_generic_param_rib(
19512007
&generics.params,
19522008
AssocItemRibKind,
1953-
LifetimeRibKind::Generics { parent: item.id, kind: LifetimeBinderKind::Function },
2009+
LifetimeRibKind::Generics { parent: item.id, span: generics.span, kind: LifetimeBinderKind::Function },
19542010
|this| {
19552011
// If this is a trait impl, ensure the method
19562012
// exists in trait
@@ -1978,7 +2034,7 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
19782034
this.with_generic_param_rib(
19792035
&generics.params,
19802036
AssocItemRibKind,
1981-
LifetimeRibKind::Generics { parent: item.id, kind: LifetimeBinderKind::Item },
2037+
LifetimeRibKind::Generics { parent: item.id, span: generics.span, kind: LifetimeBinderKind::Item },
19822038
|this| {
19832039
// If this is a trait impl, ensure the type
19842040
// exists in trait

compiler/rustc_resolve/src/late/diagnostics.rs

Lines changed: 75 additions & 63 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
use crate::diagnostics::{ImportSuggestion, LabelSuggestion, TypoSuggestion};
22
use crate::late::lifetimes::{ElisionFailureInfo, LifetimeContext};
33
use crate::late::{AliasPossibility, LateResolutionVisitor, RibKind};
4+
use crate::late::{LifetimeBinderKind, LifetimeRibKind};
45
use crate::path_names_to_string;
56
use crate::{CrateLint, Module, ModuleKind, ModuleOrUniformRoot};
67
use crate::{PathResult, PathSource, Segment};
@@ -1776,91 +1777,86 @@ impl<'a: 'ast, 'ast> LateResolutionVisitor<'a, '_, 'ast> {
17761777
(*ident, within_scope)
17771778
})
17781779
}
1779-
}
1780-
1781-
impl<'tcx> LifetimeContext<'_, 'tcx> {
1782-
crate fn report_missing_lifetime_specifiers(
1783-
&self,
1784-
spans: Vec<Span>,
1785-
count: usize,
1786-
) -> DiagnosticBuilder<'tcx> {
1787-
struct_span_err!(
1788-
self.tcx.sess,
1789-
spans,
1790-
E0106,
1791-
"missing lifetime specifier{}",
1792-
pluralize!(count)
1793-
)
1794-
}
17951780

1796-
crate fn emit_undeclared_lifetime_error(&self, lifetime_ref: &hir::Lifetime) {
1781+
crate fn emit_undeclared_lifetime_error(&self, lifetime_ref: &ast::Lifetime) {
1782+
debug_assert_ne!(lifetime_ref.ident.name, kw::UnderscoreLifetime);
17971783
let mut err = struct_span_err!(
1798-
self.tcx.sess,
1799-
lifetime_ref.span,
1784+
self.r.session,
1785+
lifetime_ref.ident.span,
18001786
E0261,
18011787
"use of undeclared lifetime name `{}`",
1802-
lifetime_ref
1788+
lifetime_ref.ident
18031789
);
1804-
err.span_label(lifetime_ref.span, "undeclared lifetime");
1790+
err.span_label(lifetime_ref.ident.span, "undeclared lifetime");
18051791
let mut suggests_in_band = false;
18061792
let mut suggest_note = true;
1807-
for missing in &self.missing_named_lifetime_spots {
1808-
match missing {
1809-
MissingLifetimeSpot::Generics(generics) => {
1810-
let (span, sugg) = if let Some(param) = generics.params.iter().find(|p| {
1811-
!matches!(
1812-
p.kind,
1813-
hir::GenericParamKind::Type { synthetic: true, .. }
1814-
| hir::GenericParamKind::Lifetime {
1815-
kind: hir::LifetimeParamKind::Elided,
1816-
}
1817-
)
1818-
}) {
1819-
(param.span.shrink_to_lo(), format!("{}, ", lifetime_ref))
1820-
} else {
1821-
suggests_in_band = true;
1822-
(generics.span, format!("<{}>", lifetime_ref))
1823-
};
1824-
if !span.from_expansion() {
1825-
err.span_suggestion(
1826-
span,
1827-
&format!("consider introducing lifetime `{}` here", lifetime_ref),
1828-
sugg,
1829-
Applicability::MaybeIncorrect,
1830-
);
1831-
} else if suggest_note {
1832-
suggest_note = false; // Avoid displaying the same help multiple times.
1833-
err.span_label(
1834-
span,
1835-
&format!(
1836-
"lifetime `{}` is missing in item created through this procedural \
1837-
macro",
1838-
lifetime_ref,
1839-
),
1840-
);
1841-
}
1793+
1794+
for rib in self.lifetime_ribs.iter() {
1795+
if let LifetimeRibKind::Generics { parent: _, span, kind } = rib.kind {
1796+
if !kind.transparent_in_band() {
1797+
suggests_in_band = kind.allow_in_band();
18421798
}
1843-
MissingLifetimeSpot::HigherRanked { span, span_type } => {
1799+
1800+
if span.from_expansion() && suggest_note {
1801+
suggest_note = false; // Avoid displaying the same help multiple times.
1802+
err.span_label(
1803+
span,
1804+
&format!(
1805+
"lifetime `{}` is missing in item created through this procedural macro",
1806+
lifetime_ref.ident,
1807+
),
1808+
);
1809+
continue;
1810+
}
1811+
1812+
let higher_ranked = matches!(
1813+
kind,
1814+
LifetimeBinderKind::BareFnType
1815+
| LifetimeBinderKind::PolyTrait
1816+
| LifetimeBinderKind::WhereBound
1817+
);
1818+
let (span, sugg) = if span.is_empty() {
1819+
let sugg = format!(
1820+
"{}<{}>{}",
1821+
if higher_ranked { "for" } else { "" },
1822+
lifetime_ref.ident,
1823+
if higher_ranked { " " } else { "" },
1824+
);
1825+
(span, sugg)
1826+
} else {
1827+
let span =
1828+
self.r.session.source_map().span_through_char(span, '<').shrink_to_hi();
1829+
let sugg = format!("{}, ", lifetime_ref.ident);
1830+
(span, sugg)
1831+
};
1832+
if higher_ranked {
18441833
err.span_suggestion(
1845-
*span,
1834+
span,
18461835
&format!(
18471836
"consider making the {} lifetime-generic with a new `{}` lifetime",
1848-
span_type.descr(),
1837+
kind.descr(),
18491838
lifetime_ref
18501839
),
1851-
span_type.suggestion(&lifetime_ref.to_string()),
1840+
sugg,
18521841
Applicability::MaybeIncorrect,
18531842
);
18541843
err.note(
18551844
"for more information on higher-ranked polymorphism, visit \
18561845
https://doc.rust-lang.org/nomicon/hrtb.html",
18571846
);
1847+
} else {
1848+
err.span_suggestion(
1849+
span,
1850+
&format!("consider introducing lifetime `{}` here", lifetime_ref.ident),
1851+
sugg,
1852+
Applicability::MaybeIncorrect,
1853+
);
18581854
}
1859-
_ => {}
18601855
}
18611856
}
1862-
if self.tcx.sess.is_nightly_build()
1863-
&& !self.tcx.features().in_band_lifetimes
1857+
1858+
if self.r.session.is_nightly_build()
1859+
&& !self.r.session.features_untracked().in_band_lifetimes
18641860
&& suggests_in_band
18651861
{
18661862
err.help(
@@ -1870,6 +1866,22 @@ impl<'tcx> LifetimeContext<'_, 'tcx> {
18701866
}
18711867
err.emit();
18721868
}
1869+
}
1870+
1871+
impl<'tcx> LifetimeContext<'_, 'tcx> {
1872+
crate fn report_missing_lifetime_specifiers(
1873+
&self,
1874+
spans: Vec<Span>,
1875+
count: usize,
1876+
) -> DiagnosticBuilder<'tcx> {
1877+
struct_span_err!(
1878+
self.tcx.sess,
1879+
spans,
1880+
E0106,
1881+
"missing lifetime specifier{}",
1882+
pluralize!(count)
1883+
)
1884+
}
18731885

18741886
// FIXME(const_generics): This patches over an ICE caused by non-'static lifetimes in const
18751887
// generics. We are disallowing this until we can decide on how we want to handle non-'static

0 commit comments

Comments
 (0)