Skip to content

Commit 42dde96

Browse files
committed
Auto merge of #55162 - nikomatsakis:issue-54902-underscore-bound, r=tmandry
handle underscore bounds in unexpected places Per the discussion on #54902, I made it a hard error to use lifetime bounds in various places where they used to be permitted: - `where Foo: Bar<'_>` for example I also moved error reporting to HIR lowering and added `Error` variants to let us suppress downstream errors that result. I (imo) improved the error message wording to be clearer, as well. In the process, I fixed the ICE in #52098. Fixes #54902 Fixes #52098
2 parents 78ff609 + c294ec6 commit 42dde96

36 files changed

+910
-362
lines changed

src/librustc/hir/intravisit.rs

+3-1
Original file line numberDiff line numberDiff line change
@@ -436,7 +436,9 @@ pub fn walk_lifetime<'v, V: Visitor<'v>>(visitor: &mut V, lifetime: &'v Lifetime
436436
visitor.visit_ident(ident);
437437
}
438438
LifetimeName::Param(ParamName::Fresh(_)) |
439+
LifetimeName::Param(ParamName::Error) |
439440
LifetimeName::Static |
441+
LifetimeName::Error |
440442
LifetimeName::Implicit |
441443
LifetimeName::Underscore => {}
442444
}
@@ -747,7 +749,7 @@ pub fn walk_generic_param<'v, V: Visitor<'v>>(visitor: &mut V, param: &'v Generi
747749
walk_list!(visitor, visit_attribute, &param.attrs);
748750
match param.name {
749751
ParamName::Plain(ident) => visitor.visit_ident(ident),
750-
ParamName::Fresh(_) => {}
752+
ParamName::Error | ParamName::Fresh(_) => {}
751753
}
752754
match param.kind {
753755
GenericParamKind::Lifetime { .. } => {}

src/librustc/hir/lowering.rs

+83-17
Original file line numberDiff line numberDiff line change
@@ -315,6 +315,11 @@ enum AnonymousLifetimeMode {
315315
/// For **Deprecated** cases, report an error.
316316
CreateParameter,
317317

318+
/// Give a hard error when either `&` or `'_` is written. Used to
319+
/// rule out things like `where T: Foo<'_>`. Does not imply an
320+
/// error on default object bounds (e.g., `Box<dyn Foo>`).
321+
ReportError,
322+
318323
/// Pass responsibility to `resolve_lifetime` code for all cases.
319324
PassThrough,
320325
}
@@ -735,6 +740,10 @@ impl<'a> LoweringContext<'a> {
735740
keywords::UnderscoreLifetime.name().as_interned_str(),
736741
hir::LifetimeParamKind::Elided,
737742
),
743+
ParamName::Error => (
744+
keywords::UnderscoreLifetime.name().as_interned_str(),
745+
hir::LifetimeParamKind::Error,
746+
),
738747
};
739748

740749
// Add a definition for the in-band lifetime def
@@ -791,7 +800,7 @@ impl<'a> LoweringContext<'a> {
791800
}
792801

793802
/// When we have either an elided or `'_` lifetime in an impl
794-
/// header, we convert it to
803+
/// header, we convert it to an in-band lifetime.
795804
fn collect_fresh_in_band_lifetime(&mut self, span: Span) -> ParamName {
796805
assert!(self.is_collecting_in_band_lifetimes);
797806
let index = self.lifetimes_to_define.len();
@@ -1474,7 +1483,7 @@ impl<'a> LoweringContext<'a> {
14741483
}
14751484
}
14761485
hir::LifetimeName::Param(_) => lifetime.name,
1477-
hir::LifetimeName::Static => return,
1486+
hir::LifetimeName::Error | hir::LifetimeName::Static => return,
14781487
};
14791488

14801489
if !self.currently_bound_lifetimes.contains(&name)
@@ -2162,7 +2171,7 @@ impl<'a> LoweringContext<'a> {
21622171
}
21632172
}
21642173
hir::LifetimeName::Param(_) => lifetime.name,
2165-
hir::LifetimeName::Static => return,
2174+
hir::LifetimeName::Error | hir::LifetimeName::Static => return,
21662175
};
21672176

21682177
if !self.currently_bound_lifetimes.contains(&name) {
@@ -2293,10 +2302,12 @@ impl<'a> LoweringContext<'a> {
22932302
itctx: ImplTraitContext<'_>,
22942303
) -> hir::GenericBound {
22952304
match *tpb {
2296-
GenericBound::Trait(ref ty, modifier) => hir::GenericBound::Trait(
2297-
self.lower_poly_trait_ref(ty, itctx),
2298-
self.lower_trait_bound_modifier(modifier),
2299-
),
2305+
GenericBound::Trait(ref ty, modifier) => {
2306+
hir::GenericBound::Trait(
2307+
self.lower_poly_trait_ref(ty, itctx),
2308+
self.lower_trait_bound_modifier(modifier),
2309+
)
2310+
}
23002311
GenericBound::Outlives(ref lifetime) => {
23012312
hir::GenericBound::Outlives(self.lower_lifetime(lifetime))
23022313
}
@@ -2318,6 +2329,8 @@ impl<'a> LoweringContext<'a> {
23182329
AnonymousLifetimeMode::PassThrough => {
23192330
self.new_named_lifetime(l.id, span, hir::LifetimeName::Underscore)
23202331
}
2332+
2333+
AnonymousLifetimeMode::ReportError => self.new_error_lifetime(Some(l.id), span),
23212334
},
23222335
ident => {
23232336
self.maybe_collect_in_band_lifetime(ident);
@@ -2356,16 +2369,26 @@ impl<'a> LoweringContext<'a> {
23562369
add_bounds: &NodeMap<Vec<GenericBound>>,
23572370
mut itctx: ImplTraitContext<'_>)
23582371
-> hir::GenericParam {
2359-
let mut bounds = self.lower_param_bounds(&param.bounds, itctx.reborrow());
2372+
let mut bounds = self.with_anonymous_lifetime_mode(
2373+
AnonymousLifetimeMode::ReportError,
2374+
|this| this.lower_param_bounds(&param.bounds, itctx.reborrow()),
2375+
);
2376+
23602377
match param.kind {
23612378
GenericParamKind::Lifetime => {
23622379
let was_collecting_in_band = self.is_collecting_in_band_lifetimes;
23632380
self.is_collecting_in_band_lifetimes = false;
23642381

2365-
let lt = self.lower_lifetime(&Lifetime { id: param.id, ident: param.ident });
2382+
let lt = self.with_anonymous_lifetime_mode(
2383+
AnonymousLifetimeMode::ReportError,
2384+
|this| this.lower_lifetime(&Lifetime { id: param.id, ident: param.ident }),
2385+
);
23662386
let param_name = match lt.name {
23672387
hir::LifetimeName::Param(param_name) => param_name,
2368-
_ => hir::ParamName::Plain(lt.name.ident()),
2388+
hir::LifetimeName::Implicit
2389+
| hir::LifetimeName::Underscore
2390+
| hir::LifetimeName::Static => hir::ParamName::Plain(lt.name.ident()),
2391+
hir::LifetimeName::Error => ParamName::Error,
23692392
};
23702393
let param = hir::GenericParam {
23712394
id: lt.id,
@@ -2489,13 +2512,18 @@ impl<'a> LoweringContext<'a> {
24892512
}
24902513

24912514
fn lower_where_clause(&mut self, wc: &WhereClause) -> hir::WhereClause {
2492-
hir::WhereClause {
2493-
id: self.lower_node_id(wc.id).node_id,
2494-
predicates: wc.predicates
2495-
.iter()
2496-
.map(|predicate| self.lower_where_predicate(predicate))
2497-
.collect(),
2498-
}
2515+
self.with_anonymous_lifetime_mode(
2516+
AnonymousLifetimeMode::ReportError,
2517+
|this| {
2518+
hir::WhereClause {
2519+
id: this.lower_node_id(wc.id).node_id,
2520+
predicates: wc.predicates
2521+
.iter()
2522+
.map(|predicate| this.lower_where_predicate(predicate))
2523+
.collect(),
2524+
}
2525+
},
2526+
)
24992527
}
25002528

25012529
fn lower_where_predicate(&mut self, pred: &WherePredicate) -> hir::WherePredicate {
@@ -4837,10 +4865,38 @@ impl<'a> LoweringContext<'a> {
48374865
}
48384866
}
48394867

4868+
AnonymousLifetimeMode::ReportError => self.new_error_lifetime(None, span),
4869+
48404870
AnonymousLifetimeMode::PassThrough => self.new_implicit_lifetime(span),
48414871
}
48424872
}
48434873

4874+
/// Report an error on illegal use of `'_` or a `&T` with no explicit lifetime;
4875+
/// return a "error lifetime".
4876+
fn new_error_lifetime(&mut self, id: Option<NodeId>, span: Span) -> hir::Lifetime {
4877+
let (id, msg, label) = match id {
4878+
Some(id) => (id, "`'_` cannot be used here", "`'_` is a reserved lifetime name"),
4879+
4880+
None => (
4881+
self.next_id().node_id,
4882+
"`&` without an explicit lifetime name cannot be used here",
4883+
"explicit lifetime name needed here",
4884+
),
4885+
};
4886+
4887+
let mut err = struct_span_err!(
4888+
self.sess,
4889+
span,
4890+
E0637,
4891+
"{}",
4892+
msg,
4893+
);
4894+
err.span_label(span, label);
4895+
err.emit();
4896+
4897+
self.new_named_lifetime(id, span, hir::LifetimeName::Error)
4898+
}
4899+
48444900
/// Invoked to create the lifetime argument(s) for a path like
48454901
/// `std::cell::Ref<T>`; note that implicit lifetimes in these
48464902
/// sorts of cases are deprecated. This may therefore report a warning or an
@@ -4855,6 +4911,12 @@ impl<'a> LoweringContext<'a> {
48554911
// impl Foo for std::cell::Ref<u32> // note lack of '_
48564912
AnonymousLifetimeMode::CreateParameter => {}
48574913

4914+
AnonymousLifetimeMode::ReportError => {
4915+
return (0..count)
4916+
.map(|_| self.new_error_lifetime(None, span))
4917+
.collect();
4918+
}
4919+
48584920
// This is the normal case.
48594921
AnonymousLifetimeMode::PassThrough => {}
48604922
}
@@ -4885,6 +4947,10 @@ impl<'a> LoweringContext<'a> {
48854947
// `resolve_lifetime` has the code to make that happen.
48864948
AnonymousLifetimeMode::CreateParameter => {}
48874949

4950+
AnonymousLifetimeMode::ReportError => {
4951+
// ReportError applies to explicit use of `'_`.
4952+
}
4953+
48884954
// This is the normal case.
48894955
AnonymousLifetimeMode::PassThrough => {}
48904956
}

src/librustc/hir/mod.rs

+15-2
Original file line numberDiff line numberDiff line change
@@ -208,13 +208,18 @@ pub enum ParamName {
208208
/// where `'f` is something like `Fresh(0)`. The indices are
209209
/// unique per impl, but not necessarily continuous.
210210
Fresh(usize),
211+
212+
/// Indicates an illegal name was given and an error has been
213+
/// repored (so we should squelch other derived errors). Occurs
214+
/// when e.g. `'_` is used in the wrong place.
215+
Error,
211216
}
212217

213218
impl ParamName {
214219
pub fn ident(&self) -> Ident {
215220
match *self {
216221
ParamName::Plain(ident) => ident,
217-
ParamName::Fresh(_) => keywords::UnderscoreLifetime.ident(),
222+
ParamName::Error | ParamName::Fresh(_) => keywords::UnderscoreLifetime.ident(),
218223
}
219224
}
220225

@@ -234,6 +239,10 @@ pub enum LifetimeName {
234239
/// User typed nothing. e.g. the lifetime in `&u32`.
235240
Implicit,
236241

242+
/// Indicates an error during lowering (usually `'_` in wrong place)
243+
/// that was already reported.
244+
Error,
245+
237246
/// User typed `'_`.
238247
Underscore,
239248

@@ -245,6 +254,7 @@ impl LifetimeName {
245254
pub fn ident(&self) -> Ident {
246255
match *self {
247256
LifetimeName::Implicit => keywords::Invalid.ident(),
257+
LifetimeName::Error => keywords::Invalid.ident(),
248258
LifetimeName::Underscore => keywords::UnderscoreLifetime.ident(),
249259
LifetimeName::Static => keywords::StaticLifetime.ident(),
250260
LifetimeName::Param(param_name) => param_name.ident(),
@@ -260,7 +270,7 @@ impl LifetimeName {
260270
// in the compiler is concerned -- `Fresh(_)` variants act
261271
// equivalently to "some fresh name". They correspond to
262272
// early-bound regions on an impl, in other words.
263-
LifetimeName::Param(_) | LifetimeName::Static => false,
273+
LifetimeName::Error | LifetimeName::Param(_) | LifetimeName::Static => false,
264274
}
265275
}
266276

@@ -513,6 +523,9 @@ pub enum LifetimeParamKind {
513523
// Indication that the lifetime was elided like both cases here:
514524
// `fn foo(x: &u8) -> &'_ u8 { x }`
515525
Elided,
526+
527+
// Indication that the lifetime name was somehow in error.
528+
Error,
516529
}
517530

518531
#[derive(Clone, RustcEncodable, RustcDecodable, Debug)]

src/librustc/ich/impls_hir.rs

+5-2
Original file line numberDiff line numberDiff line change
@@ -144,14 +144,16 @@ impl<'a> HashStable<StableHashingContext<'a>> for hir::ImplItemId {
144144

145145
impl_stable_hash_for!(enum hir::ParamName {
146146
Plain(name),
147-
Fresh(index)
147+
Fresh(index),
148+
Error,
148149
});
149150

150151
impl_stable_hash_for!(enum hir::LifetimeName {
151152
Param(param_name),
152153
Implicit,
153154
Underscore,
154155
Static,
156+
Error,
155157
});
156158

157159
impl_stable_hash_for!(struct hir::Label {
@@ -210,7 +212,8 @@ impl_stable_hash_for!(struct hir::GenericParam {
210212
impl_stable_hash_for!(enum hir::LifetimeParamKind {
211213
Explicit,
212214
InBand,
213-
Elided
215+
Elided,
216+
Error,
214217
});
215218

216219
impl<'a> HashStable<StableHashingContext<'a>> for hir::GenericParamKind {

src/librustc/ich/impls_ty.rs

+3-2
Original file line numberDiff line numberDiff line change
@@ -755,8 +755,9 @@ for ::middle::resolve_lifetime::Set1<T>
755755
}
756756

757757
impl_stable_hash_for!(enum ::middle::resolve_lifetime::LifetimeDefOrigin {
758-
Explicit,
759-
InBand
758+
ExplicitOrElided,
759+
InBand,
760+
Error,
760761
});
761762

762763
impl_stable_hash_for!(enum ::middle::resolve_lifetime::Region {

0 commit comments

Comments
 (0)