diff --git a/src/librustc/hir/intravisit.rs b/src/librustc/hir/intravisit.rs index 942f1cbd6651b..95b73d5f87b39 100644 --- a/src/librustc/hir/intravisit.rs +++ b/src/librustc/hir/intravisit.rs @@ -436,7 +436,9 @@ pub fn walk_lifetime<'v, V: Visitor<'v>>(visitor: &mut V, lifetime: &'v Lifetime visitor.visit_ident(ident); } LifetimeName::Param(ParamName::Fresh(_)) | + LifetimeName::Param(ParamName::Error) | LifetimeName::Static | + LifetimeName::Error | LifetimeName::Implicit | LifetimeName::Underscore => {} } @@ -747,7 +749,7 @@ pub fn walk_generic_param<'v, V: Visitor<'v>>(visitor: &mut V, param: &'v Generi walk_list!(visitor, visit_attribute, ¶m.attrs); match param.name { ParamName::Plain(ident) => visitor.visit_ident(ident), - ParamName::Fresh(_) => {} + ParamName::Error | ParamName::Fresh(_) => {} } match param.kind { GenericParamKind::Lifetime { .. } => {} diff --git a/src/librustc/hir/lowering.rs b/src/librustc/hir/lowering.rs index 7309358091056..1fc677b0e2926 100644 --- a/src/librustc/hir/lowering.rs +++ b/src/librustc/hir/lowering.rs @@ -316,6 +316,11 @@ enum AnonymousLifetimeMode { /// For **Deprecated** cases, report an error. CreateParameter, + /// Give a hard error when either `&` or `'_` is written. Used to + /// rule out things like `where T: Foo<'_>`. Does not imply an + /// error on default object bounds (e.g., `Box`). + ReportError, + /// Pass responsibility to `resolve_lifetime` code for all cases. PassThrough, } @@ -736,6 +741,10 @@ impl<'a> LoweringContext<'a> { keywords::UnderscoreLifetime.name().as_interned_str(), hir::LifetimeParamKind::Elided, ), + ParamName::Error => ( + keywords::UnderscoreLifetime.name().as_interned_str(), + hir::LifetimeParamKind::Error, + ), }; // Add a definition for the in-band lifetime def @@ -792,7 +801,7 @@ impl<'a> LoweringContext<'a> { } /// When we have either an elided or `'_` lifetime in an impl - /// header, we convert it to + /// header, we convert it to an in-band lifetime. fn collect_fresh_in_band_lifetime(&mut self, span: Span) -> ParamName { assert!(self.is_collecting_in_band_lifetimes); let index = self.lifetimes_to_define.len(); @@ -1475,7 +1484,7 @@ impl<'a> LoweringContext<'a> { } } hir::LifetimeName::Param(_) => lifetime.name, - hir::LifetimeName::Static => return, + hir::LifetimeName::Error | hir::LifetimeName::Static => return, }; if !self.currently_bound_lifetimes.contains(&name) @@ -2163,7 +2172,7 @@ impl<'a> LoweringContext<'a> { } } hir::LifetimeName::Param(_) => lifetime.name, - hir::LifetimeName::Static => return, + hir::LifetimeName::Error | hir::LifetimeName::Static => return, }; if !self.currently_bound_lifetimes.contains(&name) { @@ -2294,10 +2303,12 @@ impl<'a> LoweringContext<'a> { itctx: ImplTraitContext<'_>, ) -> hir::GenericBound { match *tpb { - GenericBound::Trait(ref ty, modifier) => hir::GenericBound::Trait( - self.lower_poly_trait_ref(ty, itctx), - self.lower_trait_bound_modifier(modifier), - ), + GenericBound::Trait(ref ty, modifier) => { + hir::GenericBound::Trait( + self.lower_poly_trait_ref(ty, itctx), + self.lower_trait_bound_modifier(modifier), + ) + } GenericBound::Outlives(ref lifetime) => { hir::GenericBound::Outlives(self.lower_lifetime(lifetime)) } @@ -2319,6 +2330,8 @@ impl<'a> LoweringContext<'a> { AnonymousLifetimeMode::PassThrough => { self.new_named_lifetime(l.id, span, hir::LifetimeName::Underscore) } + + AnonymousLifetimeMode::ReportError => self.new_error_lifetime(Some(l.id), span), }, ident => { self.maybe_collect_in_band_lifetime(ident); @@ -2357,16 +2370,26 @@ impl<'a> LoweringContext<'a> { add_bounds: &NodeMap>, mut itctx: ImplTraitContext<'_>) -> hir::GenericParam { - let mut bounds = self.lower_param_bounds(¶m.bounds, itctx.reborrow()); + let mut bounds = self.with_anonymous_lifetime_mode( + AnonymousLifetimeMode::ReportError, + |this| this.lower_param_bounds(¶m.bounds, itctx.reborrow()), + ); + match param.kind { GenericParamKind::Lifetime => { let was_collecting_in_band = self.is_collecting_in_band_lifetimes; self.is_collecting_in_band_lifetimes = false; - let lt = self.lower_lifetime(&Lifetime { id: param.id, ident: param.ident }); + let lt = self.with_anonymous_lifetime_mode( + AnonymousLifetimeMode::ReportError, + |this| this.lower_lifetime(&Lifetime { id: param.id, ident: param.ident }), + ); let param_name = match lt.name { hir::LifetimeName::Param(param_name) => param_name, - _ => hir::ParamName::Plain(lt.name.ident()), + hir::LifetimeName::Implicit + | hir::LifetimeName::Underscore + | hir::LifetimeName::Static => hir::ParamName::Plain(lt.name.ident()), + hir::LifetimeName::Error => ParamName::Error, }; let param = hir::GenericParam { id: lt.id, @@ -2490,13 +2513,18 @@ impl<'a> LoweringContext<'a> { } fn lower_where_clause(&mut self, wc: &WhereClause) -> hir::WhereClause { - hir::WhereClause { - id: self.lower_node_id(wc.id).node_id, - predicates: wc.predicates - .iter() - .map(|predicate| self.lower_where_predicate(predicate)) - .collect(), - } + self.with_anonymous_lifetime_mode( + AnonymousLifetimeMode::ReportError, + |this| { + hir::WhereClause { + id: this.lower_node_id(wc.id).node_id, + predicates: wc.predicates + .iter() + .map(|predicate| this.lower_where_predicate(predicate)) + .collect(), + } + }, + ) } fn lower_where_predicate(&mut self, pred: &WherePredicate) -> hir::WherePredicate { @@ -4839,10 +4867,38 @@ impl<'a> LoweringContext<'a> { } } + AnonymousLifetimeMode::ReportError => self.new_error_lifetime(None, span), + AnonymousLifetimeMode::PassThrough => self.new_implicit_lifetime(span), } } + /// Report an error on illegal use of `'_` or a `&T` with no explicit lifetime; + /// return a "error lifetime". + fn new_error_lifetime(&mut self, id: Option, span: Span) -> hir::Lifetime { + let (id, msg, label) = match id { + Some(id) => (id, "`'_` cannot be used here", "`'_` is a reserved lifetime name"), + + None => ( + self.next_id().node_id, + "`&` without an explicit lifetime name cannot be used here", + "explicit lifetime name needed here", + ), + }; + + let mut err = struct_span_err!( + self.sess, + span, + E0637, + "{}", + msg, + ); + err.span_label(span, label); + err.emit(); + + self.new_named_lifetime(id, span, hir::LifetimeName::Error) + } + /// Invoked to create the lifetime argument(s) for a path like /// `std::cell::Ref`; note that implicit lifetimes in these /// sorts of cases are deprecated. This may therefore report a warning or an @@ -4857,6 +4913,12 @@ impl<'a> LoweringContext<'a> { // impl Foo for std::cell::Ref // note lack of '_ AnonymousLifetimeMode::CreateParameter => {} + AnonymousLifetimeMode::ReportError => { + return (0..count) + .map(|_| self.new_error_lifetime(None, span)) + .collect(); + } + // This is the normal case. AnonymousLifetimeMode::PassThrough => {} } @@ -4887,6 +4949,10 @@ impl<'a> LoweringContext<'a> { // `resolve_lifetime` has the code to make that happen. AnonymousLifetimeMode::CreateParameter => {} + AnonymousLifetimeMode::ReportError => { + // ReportError applies to explicit use of `'_`. + } + // This is the normal case. AnonymousLifetimeMode::PassThrough => {} } diff --git a/src/librustc/hir/mod.rs b/src/librustc/hir/mod.rs index c57c26434e32a..01b68ae669b67 100644 --- a/src/librustc/hir/mod.rs +++ b/src/librustc/hir/mod.rs @@ -208,13 +208,18 @@ pub enum ParamName { /// where `'f` is something like `Fresh(0)`. The indices are /// unique per impl, but not necessarily continuous. Fresh(usize), + + /// Indicates an illegal name was given and an error has been + /// repored (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(_) => keywords::UnderscoreLifetime.ident(), + ParamName::Error | ParamName::Fresh(_) => keywords::UnderscoreLifetime.ident(), } } @@ -234,6 +239,10 @@ pub enum LifetimeName { /// User typed nothing. e.g. the lifetime in `&u32`. Implicit, + /// Indicates an error during lowering (usually `'_` in wrong place) + /// that was already reported. + Error, + /// User typed `'_`. Underscore, @@ -245,6 +254,7 @@ impl LifetimeName { pub fn ident(&self) -> Ident { match *self { LifetimeName::Implicit => keywords::Invalid.ident(), + LifetimeName::Error => keywords::Invalid.ident(), LifetimeName::Underscore => keywords::UnderscoreLifetime.ident(), LifetimeName::Static => keywords::StaticLifetime.ident(), LifetimeName::Param(param_name) => param_name.ident(), @@ -260,7 +270,7 @@ impl LifetimeName { // in the compiler is concerned -- `Fresh(_)` variants act // equivalently to "some fresh name". They correspond to // early-bound regions on an impl, in other words. - LifetimeName::Param(_) | LifetimeName::Static => false, + LifetimeName::Error | LifetimeName::Param(_) | LifetimeName::Static => false, } } @@ -513,6 +523,9 @@ pub enum LifetimeParamKind { // Indication that the lifetime was elided like both cases here: // `fn foo(x: &u8) -> &'_ u8 { x }` Elided, + + // Indication that the lifetime name was somehow in error. + Error, } #[derive(Clone, RustcEncodable, RustcDecodable, Debug)] diff --git a/src/librustc/ich/impls_hir.rs b/src/librustc/ich/impls_hir.rs index da9604702dfa3..fe663c68cd50b 100644 --- a/src/librustc/ich/impls_hir.rs +++ b/src/librustc/ich/impls_hir.rs @@ -144,7 +144,8 @@ impl<'a> HashStable> for hir::ImplItemId { impl_stable_hash_for!(enum hir::ParamName { Plain(name), - Fresh(index) + Fresh(index), + Error, }); impl_stable_hash_for!(enum hir::LifetimeName { @@ -152,6 +153,7 @@ impl_stable_hash_for!(enum hir::LifetimeName { Implicit, Underscore, Static, + Error, }); impl_stable_hash_for!(struct hir::Label { @@ -210,7 +212,8 @@ impl_stable_hash_for!(struct hir::GenericParam { impl_stable_hash_for!(enum hir::LifetimeParamKind { Explicit, InBand, - Elided + Elided, + Error, }); impl<'a> HashStable> for hir::GenericParamKind { diff --git a/src/librustc/ich/impls_ty.rs b/src/librustc/ich/impls_ty.rs index f51a3e71d0741..0c8224710d396 100644 --- a/src/librustc/ich/impls_ty.rs +++ b/src/librustc/ich/impls_ty.rs @@ -755,8 +755,9 @@ for ::middle::resolve_lifetime::Set1 } impl_stable_hash_for!(enum ::middle::resolve_lifetime::LifetimeDefOrigin { - Explicit, - InBand + ExplicitOrElided, + InBand, + Error, }); impl_stable_hash_for!(enum ::middle::resolve_lifetime::Region { diff --git a/src/librustc/middle/resolve_lifetime.rs b/src/librustc/middle/resolve_lifetime.rs index 2f3fdb7966f25..b22ea3dceb367 100644 --- a/src/librustc/middle/resolve_lifetime.rs +++ b/src/librustc/middle/resolve_lifetime.rs @@ -18,8 +18,8 @@ use hir::def::Def; use hir::def_id::{CrateNum, DefId, LocalDefId, LOCAL_CRATE}; use hir::map::Map; -use hir::{GenericArg, GenericParam, ItemLocalId, LifetimeName, ParamName, Node}; -use ty::{self, TyCtxt, DefIdTree, GenericParamDefKind}; +use hir::{GenericArg, GenericParam, ItemLocalId, LifetimeName, Node, ParamName}; +use ty::{self, DefIdTree, GenericParamDefKind, TyCtxt}; use errors::{Applicability, DiagnosticBuilder}; use rustc::lint; @@ -43,22 +43,23 @@ use hir::{self, GenericParamKind, LifetimeParamKind}; /// This is used to prevent the usage of in-band lifetimes in `Fn`/`fn` syntax. #[derive(Copy, Clone, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable, Debug)] pub enum LifetimeDefOrigin { - // Explicit binders like `fn foo<'a>(x: &'a u8)` - Explicit, + // Explicit binders like `fn foo<'a>(x: &'a u8)` or elided like `impl Foo<&u32>` + ExplicitOrElided, // In-band declarations like `fn foo(x: &'a u8)` InBand, + // Some kind of erroneous origin + Error, } impl LifetimeDefOrigin { fn from_param(param: &GenericParam) -> Self { match param.kind { - GenericParamKind::Lifetime { kind } => { - if kind == LifetimeParamKind::InBand { - LifetimeDefOrigin::InBand - } else { - LifetimeDefOrigin::Explicit - } - } + GenericParamKind::Lifetime { kind } => match kind { + LifetimeParamKind::InBand => LifetimeDefOrigin::InBand, + LifetimeParamKind::Explicit => LifetimeDefOrigin::ExplicitOrElided, + LifetimeParamKind::Elided => LifetimeDefOrigin::ExplicitOrElided, + LifetimeParamKind::Error => LifetimeDefOrigin::Error, + }, _ => bug!("expected a lifetime param"), } } @@ -104,12 +105,12 @@ impl Region { let origin = LifetimeDefOrigin::from_param(param); debug!( "Region::late: param={:?} depth={:?} def_id={:?} origin={:?}", - param, - depth, - def_id, - origin, + param, depth, def_id, origin, ); - (param.name.modern(), Region::LateBound(depth, def_id, origin)) + ( + param.name.modern(), + Region::LateBound(depth, def_id, origin), + ) } fn late_anon(index: &Cell) -> Region { @@ -143,23 +144,24 @@ impl Region { fn shifted_out_to_binder(self, binder: ty::DebruijnIndex) -> Region { match self { - Region::LateBound(debruijn, id, origin) => Region::LateBound( - debruijn.shifted_out_to_binder(binder), - id, - origin, - ), - Region::LateBoundAnon(debruijn, index) => Region::LateBoundAnon( - debruijn.shifted_out_to_binder(binder), - index, - ), + Region::LateBound(debruijn, id, origin) => { + Region::LateBound(debruijn.shifted_out_to_binder(binder), id, origin) + } + Region::LateBoundAnon(debruijn, index) => { + Region::LateBoundAnon(debruijn.shifted_out_to_binder(binder), index) + } _ => self, } } fn subst<'a, L>(self, mut params: L, map: &NamedRegionMap) -> Option - where L: Iterator { + where + L: Iterator, + { if let Region::EarlyBound(index, _, _) = self { - params.nth(index as usize).and_then(|lifetime| map.defs.get(&lifetime.id).cloned()) + params + .nth(index as usize) + .and_then(|lifetime| map.defs.get(&lifetime.id).cloned()) } else { Some(self) } @@ -361,17 +363,17 @@ pub fn provide(providers: &mut ty::query::Providers<'_>) { is_late_bound_map: |tcx, id| { let id = LocalDefId::from_def_id(DefId::local(id)); // (*) tcx.resolve_lifetimes(LOCAL_CRATE) - .late_bound - .get(&id) - .cloned() + .late_bound + .get(&id) + .cloned() }, object_lifetime_defaults_map: |tcx, id| { let id = LocalDefId::from_def_id(DefId::local(id)); // (*) tcx.resolve_lifetimes(LOCAL_CRATE) - .object_lifetime_defaults - .get(&id) - .cloned() + .object_lifetime_defaults + .get(&id) + .cloned() }, ..*providers @@ -405,14 +407,16 @@ fn resolve_lifetimes<'tcx>( } for k in named_region_map.late_bound { let hir_id = tcx.hir.node_to_hir_id(k); - let map = rl.late_bound.entry(hir_id.owner_local_def_id()).or_default(); + let map = rl.late_bound + .entry(hir_id.owner_local_def_id()) + .or_default(); Lrc::get_mut(map).unwrap().insert(hir_id.local_id); } for (k, v) in named_region_map.object_lifetime_defaults { let hir_id = tcx.hir.node_to_hir_id(k); let map = rl.object_lifetime_defaults - .entry(hir_id.owner_local_def_id()) - .or_default(); + .entry(hir_id.owner_local_def_id()) + .or_default(); Lrc::get_mut(map) .unwrap() .insert(hir_id.local_id, Lrc::new(v)); @@ -495,13 +499,20 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> { }; self.with(scope, |_, this| intravisit::walk_item(this, item)); } - hir::ItemKind::Existential(hir::ExistTy { impl_trait_fn: Some(_), .. }) => { + hir::ItemKind::Existential(hir::ExistTy { + impl_trait_fn: Some(_), + .. + }) => { // currently existential type declarations are just generated from impl Trait // items. doing anything on this node is irrelevant, as we currently don't need // it. } hir::ItemKind::Ty(_, ref generics) - | hir::ItemKind::Existential(hir::ExistTy { impl_trait_fn: None, ref generics, .. }) + | hir::ItemKind::Existential(hir::ExistTy { + impl_trait_fn: None, + ref generics, + .. + }) | hir::ItemKind::Enum(_, ref generics) | hir::ItemKind::Struct(_, ref generics) | hir::ItemKind::Union(_, ref generics) @@ -521,15 +532,19 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> { 0 }; let mut type_count = 0; - let lifetimes = generics.params.iter().filter_map(|param| match param.kind { - GenericParamKind::Lifetime { .. } => { - Some(Region::early(&self.tcx.hir, &mut index, param)) - } - GenericParamKind::Type { .. } => { - type_count += 1; - None - } - }).collect(); + let lifetimes = generics + .params + .iter() + .filter_map(|param| match param.kind { + GenericParamKind::Lifetime { .. } => { + Some(Region::early(&self.tcx.hir, &mut index, param)) + } + GenericParamKind::Type { .. } => { + type_count += 1; + None + } + }) + .collect(); let scope = Scope::Binder { lifetimes, next_early_index: index + type_count, @@ -569,12 +584,15 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> { let was_in_fn_syntax = self.is_in_fn_syntax; self.is_in_fn_syntax = true; let scope = Scope::Binder { - lifetimes: c.generic_params.iter().filter_map(|param| match param.kind { - GenericParamKind::Lifetime { .. } => { - Some(Region::late(&self.tcx.hir, param)) - } - _ => None, - }).collect(), + lifetimes: c.generic_params + .iter() + .filter_map(|param| match param.kind { + GenericParamKind::Lifetime { .. } => { + Some(Region::late(&self.tcx.hir, param)) + } + _ => None, + }) + .collect(), s: self.scope, next_early_index, track_lifetime_uses: true, @@ -612,6 +630,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> { // If the user wrote an explicit name, use that. self.visit_lifetime(lifetime); } + LifetimeName::Error => {} } } hir::TyKind::Rptr(ref lifetime_ref, ref mt) => { @@ -631,19 +650,19 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> { let (generics, bounds) = match self.tcx.hir.expect_item(item_id.id).node { // named existential types are reached via TyKind::Path // this arm is for `impl Trait` in the types of statics, constants and locals - hir::ItemKind::Existential(hir::ExistTy{ impl_trait_fn: None, .. }) => { + hir::ItemKind::Existential(hir::ExistTy { + impl_trait_fn: None, + .. + }) => { intravisit::walk_ty(self, ty); return; - }, + } // RPIT (return position impl trait) - hir::ItemKind::Existential(hir::ExistTy{ + hir::ItemKind::Existential(hir::ExistTy { ref generics, ref bounds, .. - }) => ( - generics, - bounds, - ), + }) => (generics, bounds), ref i => bug!("impl Trait pointed to non-existential type?? {:#?}", i), }; @@ -774,15 +793,19 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> { let mut index = self.next_early_index(); debug!("visit_ty: index = {}", index); let mut type_count = 0; - let lifetimes = generics.params.iter().filter_map(|param| match param.kind { - GenericParamKind::Lifetime { .. } => { - Some(Region::early(&self.tcx.hir, &mut index, param)) - } - GenericParamKind::Type { .. } => { - type_count += 1; - None - } - }).collect(); + let lifetimes = generics + .params + .iter() + .filter_map(|param| match param.kind { + GenericParamKind::Lifetime { .. } => { + Some(Region::early(&self.tcx.hir, &mut index, param)) + } + GenericParamKind::Type { .. } => { + type_count += 1; + None + } + }) + .collect(); let scope = Scope::Binder { lifetimes, next_early_index: index + type_count, @@ -825,15 +848,19 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> { let mut index = self.next_early_index(); let mut next_early_index = index; debug!("visit_ty: index = {}", index); - let lifetimes = generics.params.iter().filter_map(|param| match param.kind { - GenericParamKind::Lifetime { .. } => { - Some(Region::early(&self.tcx.hir, &mut index, param)) - } - GenericParamKind::Type { .. } => { - next_early_index += 1; - None - } - }).collect(); + let lifetimes = generics + .params + .iter() + .filter_map(|param| match param.kind { + GenericParamKind::Lifetime { .. } => { + Some(Region::early(&self.tcx.hir, &mut index, param)) + } + GenericParamKind::Type { .. } => { + next_early_index += 1; + None + } + }) + .collect(); let scope = Scope::Binder { lifetimes, next_early_index, @@ -851,15 +878,19 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> { let mut index = self.next_early_index(); let mut next_early_index = index; debug!("visit_ty: index = {}", index); - let lifetimes = generics.params.iter().filter_map(|param| match param.kind { - GenericParamKind::Lifetime { .. } => { - Some(Region::early(&self.tcx.hir, &mut index, param)) - } - GenericParamKind::Type { .. } => { - next_early_index += 1; - None - } - }).collect(); + let lifetimes = generics + .params + .iter() + .filter_map(|param| match param.kind { + GenericParamKind::Lifetime { .. } => { + Some(Region::early(&self.tcx.hir, &mut index, param)) + } + GenericParamKind::Type { .. } => { + next_early_index += 1; + None + } + }) + .collect(); let scope = Scope::Binder { lifetimes, @@ -933,13 +964,15 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> { ref bound_generic_params, .. }) => { - let lifetimes: FxHashMap<_, _> = bound_generic_params.iter() + let lifetimes: FxHashMap<_, _> = bound_generic_params + .iter() .filter_map(|param| match param.kind { GenericParamKind::Lifetime { .. } => { Some(Region::late(&self.tcx.hir, param)) } _ => None, - }).collect(); + }) + .collect(); if !lifetimes.is_empty() { self.trait_ref_hack = true; let next_early_index = self.next_early_index(); @@ -989,15 +1022,12 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> { ) { debug!("visit_poly_trait_ref trait_ref={:?}", trait_ref); - if !self.trait_ref_hack - || trait_ref - .bound_generic_params - .iter() - .any(|param| match param.kind { - GenericParamKind::Lifetime { .. } => true, - _ => false, - }) - { + if !self.trait_ref_hack || trait_ref.bound_generic_params.iter().any(|param| { + match param.kind { + GenericParamKind::Lifetime { .. } => true, + _ => false, + } + }) { if self.trait_ref_hack { span_err!( self.tcx.sess, @@ -1008,13 +1038,16 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> { } let next_early_index = self.next_early_index(); let scope = Scope::Binder { - lifetimes: trait_ref.bound_generic_params.iter() + lifetimes: trait_ref + .bound_generic_params + .iter() .filter_map(|param| match param.kind { GenericParamKind::Lifetime { .. } => { Some(Region::late(&self.tcx.hir, param)) } _ => None, - }).collect(), + }) + .collect(), s: self.scope, next_early_index, track_lifetime_uses: true, @@ -1079,29 +1112,30 @@ impl ShadowKind { } } -fn check_mixed_explicit_and_in_band_defs( - tcx: TyCtxt<'_, '_, '_>, - params: &P<[hir::GenericParam]>, -) { - let lifetime_params: Vec<_> = params.iter().filter_map(|param| match param.kind { - GenericParamKind::Lifetime { kind, .. } => Some((kind, param.span)), - _ => None, - }).collect(); - let explicit = lifetime_params.iter().find(|(kind, _)| *kind == LifetimeParamKind::Explicit); - let in_band = lifetime_params.iter().find(|(kind, _)| *kind == LifetimeParamKind::InBand); - - if let (Some((_, explicit_span)), Some((_, in_band_span))) - = (explicit, in_band) { +fn check_mixed_explicit_and_in_band_defs(tcx: TyCtxt<'_, '_, '_>, params: &P<[hir::GenericParam]>) { + let lifetime_params: Vec<_> = params + .iter() + .filter_map(|param| match param.kind { + GenericParamKind::Lifetime { kind, .. } => Some((kind, param.span)), + _ => None, + }) + .collect(); + let explicit = lifetime_params + .iter() + .find(|(kind, _)| *kind == LifetimeParamKind::Explicit); + let in_band = lifetime_params + .iter() + .find(|(kind, _)| *kind == LifetimeParamKind::InBand); + + if let (Some((_, explicit_span)), Some((_, in_band_span))) = (explicit, in_band) { struct_span_err!( tcx.sess, *in_band_span, E0688, "cannot mix in-band and explicit lifetime definitions" - ).span_label( - *in_band_span, - "in-band lifetime definition here", - ).span_label(*explicit_span, "explicit lifetime definition here") - .emit(); + ).span_label(*in_band_span, "in-band lifetime definition here") + .span_label(*explicit_span, "explicit lifetime definition here") + .emit(); } } @@ -1187,8 +1221,9 @@ fn extract_labels(ctxt: &mut LifetimeContext<'_, '_>, body: &hir::Body) { fn expression_label(ex: &hir::Expr) -> Option { match ex.node { - hir::ExprKind::While(.., Some(label)) | - hir::ExprKind::Loop(_, Some(label), _) => Some(label.ident), + hir::ExprKind::While(.., Some(label)) | hir::ExprKind::Loop(_, Some(label), _) => { + Some(label.ident) + } _ => None, } } @@ -1241,7 +1276,11 @@ fn compute_object_lifetime_defaults( hir::ItemKind::Struct(_, ref generics) | hir::ItemKind::Union(_, ref generics) | hir::ItemKind::Enum(_, ref generics) - | hir::ItemKind::Existential(hir::ExistTy { ref generics, impl_trait_fn: None, .. }) + | hir::ItemKind::Existential(hir::ExistTy { + ref generics, + impl_trait_fn: None, + .. + }) | hir::ItemKind::Ty(_, ref generics) | hir::ItemKind::Trait(_, _, ref generics, ..) => { let result = object_lifetime_defaults_for_item(tcx, generics); @@ -1253,8 +1292,10 @@ fn compute_object_lifetime_defaults( .map(|set| match *set { Set1::Empty => "BaseDefault".into(), Set1::One(Region::Static) => "'static".into(), - Set1::One(Region::EarlyBound(mut i, _, _)) => { - generics.params.iter().find_map(|param| match param.kind { + Set1::One(Region::EarlyBound(mut i, _, _)) => generics + .params + .iter() + .find_map(|param| match param.kind { GenericParamKind::Lifetime { .. } => { if i == 0 { return Some(param.name.ident().to_string().into()); @@ -1263,8 +1304,8 @@ fn compute_object_lifetime_defaults( None } _ => None, - }).unwrap() - } + }) + .unwrap(), Set1::One(_) => bug!(), Set1::Many => "Ambiguous".into(), }) @@ -1296,66 +1337,70 @@ fn object_lifetime_defaults_for_item( } } - generics.params.iter().filter_map(|param| match param.kind { - GenericParamKind::Lifetime { .. } => None, - GenericParamKind::Type { .. } => { - let mut set = Set1::Empty; + generics + .params + .iter() + .filter_map(|param| match param.kind { + GenericParamKind::Lifetime { .. } => None, + GenericParamKind::Type { .. } => { + let mut set = Set1::Empty; - add_bounds(&mut set, ¶m.bounds); + add_bounds(&mut set, ¶m.bounds); - let param_def_id = tcx.hir.local_def_id(param.id); - for predicate in &generics.where_clause.predicates { - // Look for `type: ...` where clauses. - let data = match *predicate { - hir::WherePredicate::BoundPredicate(ref data) => data, - _ => continue, - }; + let param_def_id = tcx.hir.local_def_id(param.id); + for predicate in &generics.where_clause.predicates { + // Look for `type: ...` where clauses. + let data = match *predicate { + hir::WherePredicate::BoundPredicate(ref data) => data, + _ => continue, + }; - // Ignore `for<'a> type: ...` as they can change what - // lifetimes mean (although we could "just" handle it). - if !data.bound_generic_params.is_empty() { - continue; - } + // Ignore `for<'a> type: ...` as they can change what + // lifetimes mean (although we could "just" handle it). + if !data.bound_generic_params.is_empty() { + continue; + } - let def = match data.bounded_ty.node { - hir::TyKind::Path(hir::QPath::Resolved(None, ref path)) => path.def, - _ => continue, - }; + let def = match data.bounded_ty.node { + hir::TyKind::Path(hir::QPath::Resolved(None, ref path)) => path.def, + _ => continue, + }; - if def == Def::TyParam(param_def_id) { - add_bounds(&mut set, &data.bounds); + if def == Def::TyParam(param_def_id) { + add_bounds(&mut set, &data.bounds); + } } - } - Some(match set { - Set1::Empty => Set1::Empty, - Set1::One(name) => { - if name == hir::LifetimeName::Static { - Set1::One(Region::Static) - } else { - generics.params.iter().filter_map(|param| match param.kind { - GenericParamKind::Lifetime { .. } => { - Some(( - param.id, - hir::LifetimeName::Param(param.name), - LifetimeDefOrigin::from_param(param), - )) - } - _ => None, - }) - .enumerate() - .find(|&(_, (_, lt_name, _))| lt_name == name) - .map_or(Set1::Many, |(i, (id, _, origin))| { - let def_id = tcx.hir.local_def_id(id); - Set1::One(Region::EarlyBound(i as u32, def_id, origin)) - }) + Some(match set { + Set1::Empty => Set1::Empty, + Set1::One(name) => { + if name == hir::LifetimeName::Static { + Set1::One(Region::Static) + } else { + generics + .params + .iter() + .filter_map(|param| match param.kind { + GenericParamKind::Lifetime { .. } => Some(( + param.id, + hir::LifetimeName::Param(param.name), + LifetimeDefOrigin::from_param(param), + )), + _ => None, + }) + .enumerate() + .find(|&(_, (_, lt_name, _))| lt_name == name) + .map_or(Set1::Many, |(i, (id, _, origin))| { + let def_id = tcx.hir.local_def_id(id); + Set1::One(Region::EarlyBound(i as u32, def_id, origin)) + }) + } } - } - Set1::Many => Set1::Many, - }) - } - }) - .collect() + Set1::Many => Set1::Many, + }) + } + }) + .collect() } impl<'a, 'tcx> LifetimeContext<'a, 'tcx> { @@ -1405,20 +1450,19 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> { // if sole lifetime, remove the `<>` brackets Some(generics.span) } else { - generics.params.iter().enumerate() - .find_map(|(i, param)| { - if param.name.ident() == name { - // We also want to delete a leading or trailing comma - // as appropriate - if i >= generics.params.len() - 1 { - Some(generics.params[i-1].span.shrink_to_hi().to(param.span)) - } else { - Some(param.span.to(generics.params[i+1].span.shrink_to_lo())) - } + generics.params.iter().enumerate().find_map(|(i, param)| { + if param.name.ident() == name { + // We also want to delete a leading or trailing comma + // as appropriate + if i >= generics.params.len() - 1 { + Some(generics.params[i - 1].span.shrink_to_hi().to(param.span)) } else { - None + Some(param.span.to(generics.params[i + 1].span.shrink_to_lo())) } - }) + } else { + None + } + }) } } @@ -1431,7 +1475,8 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> { } }; - let mut def_ids: Vec<_> = defined_by.values() + let mut def_ids: Vec<_> = defined_by + .values() .flat_map(|region| match region { Region::EarlyBound(_, def_id, _) | Region::LateBound(_, def_id, _) @@ -1445,21 +1490,28 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> { def_ids.sort_by_key(|&def_id| self.tcx.def_path_hash(def_id)); for def_id in def_ids { - debug!("check_uses_for_lifetimes_defined_by_scope: def_id = {:?}", def_id); + debug!( + "check_uses_for_lifetimes_defined_by_scope: def_id = {:?}", + def_id + ); let lifetimeuseset = self.lifetime_uses.remove(&def_id); - debug!("check_uses_for_lifetimes_defined_by_scope: lifetimeuseset = {:?}", - lifetimeuseset); + debug!( + "check_uses_for_lifetimes_defined_by_scope: lifetimeuseset = {:?}", + lifetimeuseset + ); match lifetimeuseset { Some(LifetimeUseSet::One(lifetime)) => { let node_id = self.tcx.hir.as_local_node_id(def_id).unwrap(); debug!("node id first={:?}", node_id); if let Some((id, span, name)) = match self.tcx.hir.get(node_id) { - Node::Lifetime(hir_lifetime) => { - Some((hir_lifetime.id, hir_lifetime.span, hir_lifetime.name.ident())) - } + Node::Lifetime(hir_lifetime) => Some(( + hir_lifetime.id, + hir_lifetime.span, + hir_lifetime.name.ident(), + )), Node::GenericParam(param) => { Some((param.id, param.span, param.name.ident())) } @@ -1483,9 +1535,11 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> { None => { let node_id = self.tcx.hir.as_local_node_id(def_id).unwrap(); if let Some((id, span, name)) = match self.tcx.hir.get(node_id) { - Node::Lifetime(hir_lifetime) => { - Some((hir_lifetime.id, hir_lifetime.span, hir_lifetime.name.ident())) - } + Node::Lifetime(hir_lifetime) => Some(( + hir_lifetime.id, + hir_lifetime.span, + hir_lifetime.name.ident(), + )), Node::GenericParam(param) => { Some((param.id, param.span, param.name.ident())) } @@ -1496,7 +1550,7 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> { lint::builtin::UNUSED_LIFETIMES, id, span, - &format!("lifetime parameter `{}` never used", name) + &format!("lifetime parameter `{}` never used", name), ); if let Some(parent_def_id) = self.tcx.parent(def_id) { if let Some(generics) = self.tcx.hir.get_generics(parent_def_id) { @@ -1506,7 +1560,7 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> { span, "remove it", String::new(), - Applicability::MachineApplicable + Applicability::MachineApplicable, ); } } @@ -1564,19 +1618,23 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> { } let mut type_count = 0; - let lifetimes = generics.params.iter().filter_map(|param| match param.kind { - GenericParamKind::Lifetime { .. } => { - if self.map.late_bound.contains(¶m.id) { - Some(Region::late(&self.tcx.hir, param)) - } else { - Some(Region::early(&self.tcx.hir, &mut index, param)) + let lifetimes = generics + .params + .iter() + .filter_map(|param| match param.kind { + GenericParamKind::Lifetime { .. } => { + if self.map.late_bound.contains(¶m.id) { + Some(Region::late(&self.tcx.hir, param)) + } else { + Some(Region::early(&self.tcx.hir, &mut index, param)) + } } - } - GenericParamKind::Type { .. } => { - type_count += 1; - None - } - }).collect(); + GenericParamKind::Type { .. } => { + type_count += 1; + None + } + }) + .collect(); let next_early_index = index + type_count; let scope = Scope::Binder { @@ -1631,6 +1689,12 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> { fn resolve_lifetime_ref(&mut self, lifetime_ref: &'tcx hir::Lifetime) { debug!("resolve_lifetime_ref(lifetime_ref={:?})", lifetime_ref); + + // If we've already reported an error, just ignore `lifetime_ref`. + if let LifetimeName::Error = lifetime_ref.name { + return; + } + // Walk up the scope chain, tracking the number of fn scopes // that we pass through, until we find a lifetime with the // given name or we run out of scopes. @@ -1649,17 +1713,20 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> { break None; } - Scope::Binder { ref lifetimes, s, .. } => { - let name = match lifetime_ref.name { - LifetimeName::Param(param_name) => param_name, + Scope::Binder { + ref lifetimes, s, .. + } => { + match lifetime_ref.name { + LifetimeName::Param(param_name) => { + if let Some(&def) = lifetimes.get(¶m_name.modern()) { + break Some(def.shifted(late_depth)); + } + } _ => bug!("expected LifetimeName::Param"), - }; - if let Some(&def) = lifetimes.get(&name.modern()) { - break Some(def.shifted(late_depth)); - } else { - late_depth += 1; - scope = s; } + + late_depth += 1; + scope = s; } Scope::Elision { s, .. } | Scope::ObjectLifetimeDefault { s, .. } => { @@ -1705,12 +1772,14 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> { "lifetimes used in `fn` or `Fn` syntax must be \ explicitly declared using `<...>` binders" ).span_label(lifetime_ref.span, "in-band lifetime definition") - .emit(); + .emit(); } Region::Static - | Region::EarlyBound(_, _, LifetimeDefOrigin::Explicit) - | Region::LateBound(_, _, LifetimeDefOrigin::Explicit) + | Region::EarlyBound(_, _, LifetimeDefOrigin::ExplicitOrElided) + | Region::LateBound(_, _, LifetimeDefOrigin::ExplicitOrElided) + | Region::EarlyBound(_, _, LifetimeDefOrigin::Error) + | Region::LateBound(_, _, LifetimeDefOrigin::Error) | Region::LateBoundAnon(..) | Region::Free(..) => {} } @@ -1725,35 +1794,33 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> { "use of undeclared lifetime name `{}`", lifetime_ref ).span_label(lifetime_ref.span, "undeclared lifetime") - .emit(); + .emit(); } } - fn visit_segment_args( - &mut self, - def: Def, - depth: usize, - generic_args: &'tcx hir::GenericArgs, - ) { + fn visit_segment_args(&mut self, def: Def, depth: usize, generic_args: &'tcx hir::GenericArgs) { if generic_args.parenthesized { let was_in_fn_syntax = self.is_in_fn_syntax; self.is_in_fn_syntax = true; - self.visit_fn_like_elision(generic_args.inputs(), - Some(&generic_args.bindings[0].ty)); + self.visit_fn_like_elision(generic_args.inputs(), Some(&generic_args.bindings[0].ty)); self.is_in_fn_syntax = was_in_fn_syntax; return; } let mut elide_lifetimes = true; - let lifetimes = generic_args.args.iter().filter_map(|arg| match arg { - hir::GenericArg::Lifetime(lt) => { - if !lt.is_elided() { - elide_lifetimes = false; + let lifetimes = generic_args + .args + .iter() + .filter_map(|arg| match arg { + hir::GenericArg::Lifetime(lt) => { + if !lt.is_elided() { + elide_lifetimes = false; + } + Some(lt) } - Some(lt) - } - _ => None, - }).collect(); + _ => None, + }) + .collect(); if elide_lifetimes { self.resolve_elided_lifetimes(lifetimes); } else { @@ -1809,33 +1876,37 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> { self.xcrate_object_lifetime_defaults .entry(def_id) .or_insert_with(|| { - tcx.generics_of(def_id).params.iter().filter_map(|param| { - match param.kind { - GenericParamDefKind::Type { object_lifetime_default, .. } => { - Some(object_lifetime_default) - } + tcx.generics_of(def_id) + .params + .iter() + .filter_map(|param| match param.kind { + GenericParamDefKind::Type { + object_lifetime_default, + .. + } => Some(object_lifetime_default), GenericParamDefKind::Lifetime => None, - } - }).collect() + }) + .collect() }) }; - unsubst.iter() - .map(|set| match *set { - Set1::Empty => if in_body { - None - } else { - Some(Region::Static) - }, - Set1::One(r) => { - let lifetimes = generic_args.args.iter().filter_map(|arg| match arg { - GenericArg::Lifetime(lt) => Some(lt), - _ => None, - }); - r.subst(lifetimes, map) - } - Set1::Many => None, - }) - .collect() + unsubst + .iter() + .map(|set| match *set { + Set1::Empty => if in_body { + None + } else { + Some(Region::Static) + }, + Set1::One(r) => { + let lifetimes = generic_args.args.iter().filter_map(|arg| match arg { + GenericArg::Lifetime(lt) => Some(lt), + _ => None, + }); + r.subst(lifetimes, map) + } + Set1::Many => None, + }) + .collect() }); let mut i = 0; @@ -1862,11 +1933,7 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> { } } - fn visit_fn_like_elision( - &mut self, - inputs: &'tcx [hir::Ty], - output: Option<&'tcx P>, - ) { + fn visit_fn_like_elision(&mut self, inputs: &'tcx [hir::Ty], output: Option<&'tcx P>) { debug!("visit_fn_like_elision: enter"); let mut arg_elide = Elide::FreshLateAnon(Cell::new(0)); let arg_scope = Scope::Elision { @@ -2126,8 +2193,7 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> { } } - fn resolve_elided_lifetimes(&mut self, - lifetime_refs: Vec<&'tcx hir::Lifetime>) { + fn resolve_elided_lifetimes(&mut self, lifetime_refs: Vec<&'tcx hir::Lifetime>) { if lifetime_refs.is_empty() { return; } @@ -2285,23 +2351,32 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> { Scope::Body { .. } | Scope::ObjectLifetimeDefault { lifetime: None, .. } => return, - Scope::ObjectLifetimeDefault { lifetime: Some(l), .. } => break l, + Scope::ObjectLifetimeDefault { + lifetime: Some(l), .. + } => break l, } }; self.insert_lifetime(lifetime_ref, lifetime.shifted(late_depth)); } - fn check_lifetime_params(&mut self, old_scope: ScopeRef<'_>, - params: &'tcx [hir::GenericParam]) { - let lifetimes: Vec<_> = params.iter().filter_map(|param| match param.kind { - GenericParamKind::Lifetime { .. } => Some((param, param.name)), - _ => None, - }).collect(); + fn check_lifetime_params( + &mut self, + old_scope: ScopeRef<'_>, + params: &'tcx [hir::GenericParam], + ) { + let lifetimes: Vec<_> = params + .iter() + .filter_map(|param| match param.kind { + GenericParamKind::Lifetime { .. } => Some((param, param.name)), + _ => None, + }) + .collect(); for (i, (lifetime_i, lifetime_i_name)) in lifetimes.iter().enumerate() { if let hir::ParamName::Plain(_) = lifetime_i_name { let name = lifetime_i_name.ident().name; - if name == keywords::UnderscoreLifetime.name() || - name == keywords::StaticLifetime.name() { + if name == keywords::UnderscoreLifetime.name() + || name == keywords::StaticLifetime.name() + { let mut err = struct_span_err!( self.tcx.sess, lifetime_i.span, @@ -2327,8 +2402,8 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> { "lifetime name `{}` declared twice in the same scope", lifetime_j.name.ident() ).span_label(lifetime_j.span, "declared twice") - .span_label(lifetime_i.span, "previous declaration here") - .emit(); + .span_label(lifetime_i.span, "previous declaration here") + .emit(); } } @@ -2338,33 +2413,34 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> { for bound in &lifetime_i.bounds { match bound { hir::GenericBound::Outlives(lt) => match lt.name { - hir::LifetimeName::Underscore => { - let mut err = struct_span_err!( - self.tcx.sess, - lt.span, - E0637, - "invalid lifetime bound name: `'_`" - ); - err.span_label(lt.span, "`'_` is a reserved lifetime name"); - err.emit(); - } + hir::LifetimeName::Underscore => self.tcx.sess.delay_span_bug( + lt.span, + "use of `'_` in illegal place, but not caught by lowering", + ), hir::LifetimeName::Static => { self.insert_lifetime(lt, Region::Static); - self.tcx.sess.struct_span_warn( - lifetime_i.span.to(lt.span), - &format!( - "unnecessary lifetime parameter `{}`", + self.tcx + .sess + .struct_span_warn( + lifetime_i.span.to(lt.span), + &format!( + "unnecessary lifetime parameter `{}`", + lifetime_i.name.ident(), + ), + ) + .help(&format!( + "you can use the `'static` lifetime directly, in place of `{}`", lifetime_i.name.ident(), - ), - ).help(&format!( - "you can use the `'static` lifetime directly, in place of `{}`", - lifetime_i.name.ident(), - )).emit(); + )) + .emit(); } hir::LifetimeName::Param(_) | hir::LifetimeName::Implicit => { self.resolve_lifetime_ref(lt); } - } + hir::LifetimeName::Error => { + // No need to do anything, error already reported. + } + }, _ => bug!(), } } @@ -2533,8 +2609,10 @@ fn insert_late_bound_lifetimes( decl: &hir::FnDecl, generics: &hir::Generics, ) { - debug!("insert_late_bound_lifetimes(decl={:?}, generics={:?})", - decl, generics); + debug!( + "insert_late_bound_lifetimes(decl={:?}, generics={:?})", + decl, generics + ); let mut constrained_by_input = ConstrainedCollector { regions: FxHashSet(), @@ -2548,8 +2626,10 @@ fn insert_late_bound_lifetimes( }; intravisit::walk_fn_ret_ty(&mut appears_in_output, &decl.output); - debug!("insert_late_bound_lifetimes: constrained_by_input={:?}", - constrained_by_input.regions); + debug!( + "insert_late_bound_lifetimes: constrained_by_input={:?}", + constrained_by_input.regions + ); // Walk the lifetimes that appear in where clauses. // @@ -2565,7 +2645,8 @@ fn insert_late_bound_lifetimes( if !param.bounds.is_empty() { // `'a: 'b` means both `'a` and `'b` are referenced appears_in_where_clause - .regions.insert(hir::LifetimeName::Param(param.name.modern())); + .regions + .insert(hir::LifetimeName::Param(param.name.modern())); } } } @@ -2600,9 +2681,11 @@ fn insert_late_bound_lifetimes( continue; } - debug!("insert_late_bound_lifetimes: lifetime {:?} with id {:?} is late-bound", - param.name.ident(), - param.id); + debug!( + "insert_late_bound_lifetimes: lifetime {:?} with id {:?} is late-bound", + param.name.ident(), + param.id + ); let inserted = map.late_bound.insert(param.id); assert!(inserted, "visited lifetime {:?} twice", param.id); diff --git a/src/librustc_lint/builtin.rs b/src/librustc_lint/builtin.rs index d18edf22dc10c..bc5f688729c36 100644 --- a/src/librustc_lint/builtin.rs +++ b/src/librustc_lint/builtin.rs @@ -2074,6 +2074,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for ExplicitOutlivesRequirements { hir::GenericParamKind::Type { .. } => { match param.name { hir::ParamName::Fresh(_) => { continue; }, + hir::ParamName::Error => { continue; }, hir::ParamName::Plain(name) => name.to_string() } } diff --git a/src/librustc_mir/borrow_check/nll/region_infer/error_reporting/region_name.rs b/src/librustc_mir/borrow_check/nll/region_infer/error_reporting/region_name.rs index 65ba2f537bf21..ab80eaba69924 100644 --- a/src/librustc_mir/borrow_check/nll/region_infer/error_reporting/region_name.rs +++ b/src/librustc_mir/borrow_check/nll/region_infer/error_reporting/region_name.rs @@ -563,6 +563,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { let lifetime = self.try_match_adt_and_generic_args(substs, needle_fr, args, search_stack)?; match lifetime.name { hir::LifetimeName::Param(_) + | hir::LifetimeName::Error | hir::LifetimeName::Static | hir::LifetimeName::Underscore => { let region_name = self.synthesize_region_name(counter); diff --git a/src/librustc_typeck/check/wfcheck.rs b/src/librustc_typeck/check/wfcheck.rs index cc1906d91d4c9..713e267543269 100644 --- a/src/librustc_typeck/check/wfcheck.rs +++ b/src/librustc_typeck/check/wfcheck.rs @@ -816,7 +816,10 @@ fn check_variances_for_type_defn<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, } let param = &hir_generics.params[index]; - report_bivariance(tcx, param.span, param.name.ident().name); + match param.name { + hir::ParamName::Error => { } + _ => report_bivariance(tcx, param.span, param.name.ident().name), + } } } diff --git a/src/test/ui/error-codes/E0637.rs b/src/test/ui/error-codes/E0637.rs index ee6a978d169a3..b4f769a749f80 100644 --- a/src/test/ui/error-codes/E0637.rs +++ b/src/test/ui/error-codes/E0637.rs @@ -8,11 +8,11 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -struct Foo<'a: '_>(&'a u8); //~ ERROR invalid lifetime bound name: `'_` -fn foo<'a: '_>(_: &'a u8) {} //~ ERROR invalid lifetime bound name: `'_` +struct Foo<'a: '_>(&'a u8); //~ ERROR cannot be used here +fn foo<'a: '_>(_: &'a u8) {} //~ ERROR cannot be used here struct Bar<'a>(&'a u8); -impl<'a: '_> Bar<'a> { //~ ERROR invalid lifetime bound name: `'_` +impl<'a: '_> Bar<'a> { //~ ERROR cannot be used here fn bar() {} } diff --git a/src/test/ui/error-codes/E0637.stderr b/src/test/ui/error-codes/E0637.stderr index 245729376df36..2a4545fc43d08 100644 --- a/src/test/ui/error-codes/E0637.stderr +++ b/src/test/ui/error-codes/E0637.stderr @@ -1,19 +1,19 @@ -error[E0637]: invalid lifetime bound name: `'_` +error[E0637]: `'_` cannot be used here --> $DIR/E0637.rs:11:16 | -LL | struct Foo<'a: '_>(&'a u8); //~ ERROR invalid lifetime bound name: `'_` +LL | struct Foo<'a: '_>(&'a u8); //~ ERROR cannot be used here | ^^ `'_` is a reserved lifetime name -error[E0637]: invalid lifetime bound name: `'_` +error[E0637]: `'_` cannot be used here --> $DIR/E0637.rs:12:12 | -LL | fn foo<'a: '_>(_: &'a u8) {} //~ ERROR invalid lifetime bound name: `'_` +LL | fn foo<'a: '_>(_: &'a u8) {} //~ ERROR cannot be used here | ^^ `'_` is a reserved lifetime name -error[E0637]: invalid lifetime bound name: `'_` +error[E0637]: `'_` cannot be used here --> $DIR/E0637.rs:15:10 | -LL | impl<'a: '_> Bar<'a> { //~ ERROR invalid lifetime bound name: `'_` +LL | impl<'a: '_> Bar<'a> { //~ ERROR cannot be used here | ^^ `'_` is a reserved lifetime name error: aborting due to 3 previous errors diff --git a/src/test/ui/underscore-lifetime/in-binder.Rust2015.stderr b/src/test/ui/underscore-lifetime/in-binder.Rust2015.stderr new file mode 100644 index 0000000000000..a851e6b2071b2 --- /dev/null +++ b/src/test/ui/underscore-lifetime/in-binder.Rust2015.stderr @@ -0,0 +1,46 @@ +error[E0637]: `'_` cannot be used here + --> $DIR/in-binder.rs:12:6 + | +LL | impl<'_> IceCube<'_> {} + | ^^ `'_` is a reserved lifetime name + +error[E0637]: `'_` cannot be used here + --> $DIR/in-binder.rs:17:15 + | +LL | struct Struct<'_> { + | ^^ `'_` is a reserved lifetime name + +error[E0637]: `'_` cannot be used here + --> $DIR/in-binder.rs:23:11 + | +LL | enum Enum<'_> { + | ^^ `'_` is a reserved lifetime name + +error[E0637]: `'_` cannot be used here + --> $DIR/in-binder.rs:29:13 + | +LL | union Union<'_> { + | ^^ `'_` is a reserved lifetime name + +error[E0637]: `'_` cannot be used here + --> $DIR/in-binder.rs:35:13 + | +LL | trait Trait<'_> { + | ^^ `'_` is a reserved lifetime name + +error[E0637]: `'_` cannot be used here + --> $DIR/in-binder.rs:40:8 + | +LL | fn foo<'_>() { + | ^^ `'_` is a reserved lifetime name + +error[E0106]: missing lifetime specifier + --> $DIR/in-binder.rs:12:18 + | +LL | impl<'_> IceCube<'_> {} + | ^^ expected lifetime parameter + +error: aborting due to 7 previous errors + +Some errors occurred: E0106, E0637. +For more information about an error, try `rustc --explain E0106`. diff --git a/src/test/ui/underscore-lifetime/in-binder.Rust2018.stderr b/src/test/ui/underscore-lifetime/in-binder.Rust2018.stderr new file mode 100644 index 0000000000000..77da3038724b8 --- /dev/null +++ b/src/test/ui/underscore-lifetime/in-binder.Rust2018.stderr @@ -0,0 +1,39 @@ +error[E0637]: `'_` cannot be used here + --> $DIR/in-binder.rs:12:6 + | +LL | impl<'_> IceCube<'_> {} + | ^^ `'_` is a reserved lifetime name + +error[E0637]: `'_` cannot be used here + --> $DIR/in-binder.rs:17:15 + | +LL | struct Struct<'_> { + | ^^ `'_` is a reserved lifetime name + +error[E0637]: `'_` cannot be used here + --> $DIR/in-binder.rs:23:11 + | +LL | enum Enum<'_> { + | ^^ `'_` is a reserved lifetime name + +error[E0637]: `'_` cannot be used here + --> $DIR/in-binder.rs:29:13 + | +LL | union Union<'_> { + | ^^ `'_` is a reserved lifetime name + +error[E0637]: `'_` cannot be used here + --> $DIR/in-binder.rs:35:13 + | +LL | trait Trait<'_> { + | ^^ `'_` is a reserved lifetime name + +error[E0637]: `'_` cannot be used here + --> $DIR/in-binder.rs:40:8 + | +LL | fn foo<'_>() { + | ^^ `'_` is a reserved lifetime name + +error: aborting due to 6 previous errors + +For more information about this error, try `rustc --explain E0637`. diff --git a/src/test/ui/underscore-lifetime/in-binder.rs b/src/test/ui/underscore-lifetime/in-binder.rs new file mode 100644 index 0000000000000..c94947d1eab1c --- /dev/null +++ b/src/test/ui/underscore-lifetime/in-binder.rs @@ -0,0 +1,45 @@ +// Check that we error when `'_` appears as the name of a lifetime parameter. +// +// Regression test for #52098. + +// revisions: Rust2015 Rust2018 +//[Rust2018] edition:2018 + +struct IceCube<'a> { + v: Vec<&'a char> +} + +impl<'_> IceCube<'_> {} +//[Rust2015]~^ ERROR `'_` cannot be used here +//[Rust2015]~| ERROR missing lifetime specifier +//[Rust2018]~^^^ ERROR `'_` cannot be used here + +struct Struct<'_> { +//[Rust2015]~^ ERROR `'_` cannot be used here +//[Rust2018]~^^ ERROR `'_` cannot be used here + v: Vec<&'static char> +} + +enum Enum<'_> { +//[Rust2015]~^ ERROR `'_` cannot be used here +//[Rust2018]~^^ ERROR `'_` cannot be used here + Variant +} + +union Union<'_> { +//[Rust2015]~^ ERROR `'_` cannot be used here +//[Rust2018]~^^ ERROR `'_` cannot be used here + a: u32 +} + +trait Trait<'_> { +//[Rust2015]~^ ERROR `'_` cannot be used here +//[Rust2018]~^^ ERROR `'_` cannot be used here +} + +fn foo<'_>() { + //[Rust2015]~^ ERROR `'_` cannot be used here + //[Rust2018]~^^ ERROR `'_` cannot be used here +} + +fn main() {} diff --git a/src/test/ui/underscore-lifetime/in-fn-return-illegal.rs b/src/test/ui/underscore-lifetime/in-fn-return-illegal.rs new file mode 100644 index 0000000000000..09f3abd9135cb --- /dev/null +++ b/src/test/ui/underscore-lifetime/in-fn-return-illegal.rs @@ -0,0 +1,17 @@ +// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// Check that the `'_` used in structs/enums gives an error. + +use std::fmt::Debug; + +fn foo(x: &u32, y: &u32) -> &'_ u32 { loop { } } //~ ERROR missing lifetime specifier + +fn main() { } diff --git a/src/test/ui/underscore-lifetime/in-fn-return-illegal.stderr b/src/test/ui/underscore-lifetime/in-fn-return-illegal.stderr new file mode 100644 index 0000000000000..f3ba3e5292426 --- /dev/null +++ b/src/test/ui/underscore-lifetime/in-fn-return-illegal.stderr @@ -0,0 +1,11 @@ +error[E0106]: missing lifetime specifier + --> $DIR/in-fn-return-illegal.rs:15:30 + | +LL | fn foo(x: &u32, y: &u32) -> &'_ u32 { loop { } } //~ ERROR missing lifetime specifier + | ^^ expected lifetime parameter + | + = help: this function's return type contains a borrowed value, but the signature does not say whether it is borrowed from `x` or `y` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0106`. diff --git a/src/test/ui/underscore-lifetime/in-struct.rs b/src/test/ui/underscore-lifetime/in-struct.rs new file mode 100644 index 0000000000000..1c1a9ef62d594 --- /dev/null +++ b/src/test/ui/underscore-lifetime/in-struct.rs @@ -0,0 +1,23 @@ +// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// Check that the `'_` used in structs/enums gives an error. + +use std::fmt::Debug; + +struct Foo { + x: &'_ u32, //~ ERROR missing lifetime specifier +} + +enum Bar { + Variant(&'_ u32), //~ ERROR missing lifetime specifier +} + +fn main() { } diff --git a/src/test/ui/underscore-lifetime/in-struct.stderr b/src/test/ui/underscore-lifetime/in-struct.stderr new file mode 100644 index 0000000000000..d288995d4bb82 --- /dev/null +++ b/src/test/ui/underscore-lifetime/in-struct.stderr @@ -0,0 +1,15 @@ +error[E0106]: missing lifetime specifier + --> $DIR/in-struct.rs:16:9 + | +LL | x: &'_ u32, //~ ERROR missing lifetime specifier + | ^^ expected lifetime parameter + +error[E0106]: missing lifetime specifier + --> $DIR/in-struct.rs:20:14 + | +LL | Variant(&'_ u32), //~ ERROR missing lifetime specifier + | ^^ expected lifetime parameter + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0106`. diff --git a/src/test/ui/underscore-lifetime/underscore-lifetime-binders.rs b/src/test/ui/underscore-lifetime/underscore-lifetime-binders.rs index 6a6698957d9d1..2652fc62bb622 100644 --- a/src/test/ui/underscore-lifetime/underscore-lifetime-binders.rs +++ b/src/test/ui/underscore-lifetime/underscore-lifetime-binders.rs @@ -15,13 +15,13 @@ impl Foo<'_> { //~ ERROR missing lifetime specifier fn x() {} } -fn foo<'_> //~ ERROR invalid lifetime parameter name: `'_` +fn foo<'_> //~ ERROR cannot be used here (_: Foo<'_>) {} trait Meh<'a> {} impl<'a> Meh<'a> for u8 {} -fn meh() -> Box Meh<'_>> //~ ERROR invalid lifetime parameter name: `'_` +fn meh() -> Box Meh<'_>> //~ ERROR cannot be used here //~^ ERROR missing lifetime specifier { Box::new(5u8) diff --git a/src/test/ui/underscore-lifetime/underscore-lifetime-binders.stderr b/src/test/ui/underscore-lifetime/underscore-lifetime-binders.stderr index 4917c2795e39d..fc9f3e642d402 100644 --- a/src/test/ui/underscore-lifetime/underscore-lifetime-binders.stderr +++ b/src/test/ui/underscore-lifetime/underscore-lifetime-binders.stderr @@ -1,3 +1,15 @@ +error[E0637]: `'_` cannot be used here + --> $DIR/underscore-lifetime-binders.rs:18:8 + | +LL | fn foo<'_> //~ ERROR cannot be used here + | ^^ `'_` is a reserved lifetime name + +error[E0637]: `'_` cannot be used here + --> $DIR/underscore-lifetime-binders.rs:24:21 + | +LL | fn meh() -> Box Meh<'_>> //~ ERROR cannot be used here + | ^^ `'_` is a reserved lifetime name + error[E0106]: missing lifetime specifier --> $DIR/underscore-lifetime-binders.rs:12:17 | @@ -10,22 +22,10 @@ error[E0106]: missing lifetime specifier LL | impl Foo<'_> { //~ ERROR missing lifetime specifier | ^^ expected lifetime parameter -error[E0262]: invalid lifetime parameter name: `'_` - --> $DIR/underscore-lifetime-binders.rs:18:8 - | -LL | fn foo<'_> //~ ERROR invalid lifetime parameter name: `'_` - | ^^ '_ is a reserved lifetime name - -error[E0262]: invalid lifetime parameter name: `'_` - --> $DIR/underscore-lifetime-binders.rs:24:21 - | -LL | fn meh() -> Box Meh<'_>> //~ ERROR invalid lifetime parameter name: `'_` - | ^^ '_ is a reserved lifetime name - error[E0106]: missing lifetime specifier --> $DIR/underscore-lifetime-binders.rs:24:29 | -LL | fn meh() -> Box Meh<'_>> //~ ERROR invalid lifetime parameter name: `'_` +LL | fn meh() -> Box Meh<'_>> //~ ERROR cannot be used here | ^^ expected lifetime parameter | = help: this function's return type contains a borrowed value, but there is no value for it to be borrowed from @@ -41,5 +41,5 @@ LL | fn foo2(_: &'_ u8, y: &'_ u8) -> &'_ u8 { y } //~ ERROR missing lifetime sp error: aborting due to 6 previous errors -Some errors occurred: E0106, E0262. +Some errors occurred: E0106, E0637. For more information about an error, try `rustc --explain E0106`. diff --git a/src/test/ui/underscore-lifetime/underscore-outlives-bounds.rs b/src/test/ui/underscore-lifetime/underscore-outlives-bounds.rs new file mode 100644 index 0000000000000..b514ff4386075 --- /dev/null +++ b/src/test/ui/underscore-lifetime/underscore-outlives-bounds.rs @@ -0,0 +1,8 @@ +// Regression test to check that `'b: '_` gets an error, because it's +// basically useless. +// +// #54902 + +trait Foo<'a> {} +impl<'b: '_> Foo<'b> for i32 {} +fn main() { } diff --git a/src/test/ui/underscore-lifetime/underscore-outlives-bounds.stderr b/src/test/ui/underscore-lifetime/underscore-outlives-bounds.stderr new file mode 100644 index 0000000000000..4b38a26f957f9 --- /dev/null +++ b/src/test/ui/underscore-lifetime/underscore-outlives-bounds.stderr @@ -0,0 +1,9 @@ +error[E0637]: `'_` cannot be used here + --> $DIR/underscore-outlives-bounds.rs:7:10 + | +LL | impl<'b: '_> Foo<'b> for i32 {} + | ^^ `'_` is a reserved lifetime name + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0637`. diff --git a/src/test/ui/underscore-lifetime/where-clause-inherent-impl-ampersand.rs b/src/test/ui/underscore-lifetime/where-clause-inherent-impl-ampersand.rs new file mode 100644 index 0000000000000..43de30944cacb --- /dev/null +++ b/src/test/ui/underscore-lifetime/where-clause-inherent-impl-ampersand.rs @@ -0,0 +1,18 @@ +// revisions: rust2015 rust2018 +//[rust2018] edition:2018 + +trait WithType {} +trait WithRegion<'a> { } + +struct Foo { + t: T +} + +impl Foo +where + T: WithType<&u32> +//[rust2015]~^ ERROR `&` without an explicit lifetime name cannot be used here +//[rust2018]~^^ ERROR `&` without an explicit lifetime name cannot be used here +{ } + +fn main() {} diff --git a/src/test/ui/underscore-lifetime/where-clause-inherent-impl-ampersand.rust2015.stderr b/src/test/ui/underscore-lifetime/where-clause-inherent-impl-ampersand.rust2015.stderr new file mode 100644 index 0000000000000..fe726cb49c737 --- /dev/null +++ b/src/test/ui/underscore-lifetime/where-clause-inherent-impl-ampersand.rust2015.stderr @@ -0,0 +1,9 @@ +error[E0637]: `&` without an explicit lifetime name cannot be used here + --> $DIR/where-clause-inherent-impl-ampersand.rs:13:17 + | +LL | T: WithType<&u32> + | ^ explicit lifetime name needed here + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0637`. diff --git a/src/test/ui/underscore-lifetime/where-clause-inherent-impl-ampersand.rust2018.stderr b/src/test/ui/underscore-lifetime/where-clause-inherent-impl-ampersand.rust2018.stderr new file mode 100644 index 0000000000000..fe726cb49c737 --- /dev/null +++ b/src/test/ui/underscore-lifetime/where-clause-inherent-impl-ampersand.rust2018.stderr @@ -0,0 +1,9 @@ +error[E0637]: `&` without an explicit lifetime name cannot be used here + --> $DIR/where-clause-inherent-impl-ampersand.rs:13:17 + | +LL | T: WithType<&u32> + | ^ explicit lifetime name needed here + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0637`. diff --git a/src/test/ui/underscore-lifetime/where-clause-inherent-impl-underscore.rs b/src/test/ui/underscore-lifetime/where-clause-inherent-impl-underscore.rs new file mode 100644 index 0000000000000..b50cce335bd8c --- /dev/null +++ b/src/test/ui/underscore-lifetime/where-clause-inherent-impl-underscore.rs @@ -0,0 +1,18 @@ +// revisions: rust2015 rust2018 +//[rust2018] edition:2018 + +trait WithType {} +trait WithRegion<'a> { } + +struct Foo { + t: T +} + +impl Foo +where + T: WithRegion<'_> +//[rust2015]~^ ERROR `'_` cannot be used here +//[rust2018]~^^ ERROR `'_` cannot be used here +{ } + +fn main() {} diff --git a/src/test/ui/underscore-lifetime/where-clause-inherent-impl-underscore.rust2015.stderr b/src/test/ui/underscore-lifetime/where-clause-inherent-impl-underscore.rust2015.stderr new file mode 100644 index 0000000000000..95939fd6b7e03 --- /dev/null +++ b/src/test/ui/underscore-lifetime/where-clause-inherent-impl-underscore.rust2015.stderr @@ -0,0 +1,9 @@ +error[E0637]: `'_` cannot be used here + --> $DIR/where-clause-inherent-impl-underscore.rs:13:19 + | +LL | T: WithRegion<'_> + | ^^ `'_` is a reserved lifetime name + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0637`. diff --git a/src/test/ui/underscore-lifetime/where-clause-inherent-impl-underscore.rust2018.stderr b/src/test/ui/underscore-lifetime/where-clause-inherent-impl-underscore.rust2018.stderr new file mode 100644 index 0000000000000..95939fd6b7e03 --- /dev/null +++ b/src/test/ui/underscore-lifetime/where-clause-inherent-impl-underscore.rust2018.stderr @@ -0,0 +1,9 @@ +error[E0637]: `'_` cannot be used here + --> $DIR/where-clause-inherent-impl-underscore.rs:13:19 + | +LL | T: WithRegion<'_> + | ^^ `'_` is a reserved lifetime name + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0637`. diff --git a/src/test/ui/underscore-lifetime/where-clause-trait-impl-region.rs b/src/test/ui/underscore-lifetime/where-clause-trait-impl-region.rs new file mode 100644 index 0000000000000..f2d483e66e013 --- /dev/null +++ b/src/test/ui/underscore-lifetime/where-clause-trait-impl-region.rs @@ -0,0 +1,16 @@ +// revisions: rust2015 rust2018 +//[rust2018] edition:2018 + +trait WithType {} +trait WithRegion<'a> { } + +trait Foo { } + +impl Foo for Vec +where + T: WithType<&u32> +//[rust2015]~^ ERROR `&` without an explicit lifetime name cannot be used here +//[rust2018]~^^ ERROR `&` without an explicit lifetime name cannot be used here +{ } + +fn main() {} diff --git a/src/test/ui/underscore-lifetime/where-clause-trait-impl-region.rust2015.stderr b/src/test/ui/underscore-lifetime/where-clause-trait-impl-region.rust2015.stderr new file mode 100644 index 0000000000000..fbd14de21078b --- /dev/null +++ b/src/test/ui/underscore-lifetime/where-clause-trait-impl-region.rust2015.stderr @@ -0,0 +1,9 @@ +error[E0637]: `&` without an explicit lifetime name cannot be used here + --> $DIR/where-clause-trait-impl-region.rs:11:17 + | +LL | T: WithType<&u32> + | ^ explicit lifetime name needed here + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0637`. diff --git a/src/test/ui/underscore-lifetime/where-clause-trait-impl-region.rust2018.stderr b/src/test/ui/underscore-lifetime/where-clause-trait-impl-region.rust2018.stderr new file mode 100644 index 0000000000000..fbd14de21078b --- /dev/null +++ b/src/test/ui/underscore-lifetime/where-clause-trait-impl-region.rust2018.stderr @@ -0,0 +1,9 @@ +error[E0637]: `&` without an explicit lifetime name cannot be used here + --> $DIR/where-clause-trait-impl-region.rs:11:17 + | +LL | T: WithType<&u32> + | ^ explicit lifetime name needed here + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0637`. diff --git a/src/test/ui/underscore-lifetime/where-clause-trait-impl-underscore.rs b/src/test/ui/underscore-lifetime/where-clause-trait-impl-underscore.rs new file mode 100644 index 0000000000000..94e4426e822d9 --- /dev/null +++ b/src/test/ui/underscore-lifetime/where-clause-trait-impl-underscore.rs @@ -0,0 +1,16 @@ +// revisions: rust2015 rust2018 +//[rust2018] edition:2018 + +trait WithType {} +trait WithRegion<'a> { } + +trait Foo { } + +impl Foo for Vec +where + T: WithRegion<'_> +//[rust2015]~^ ERROR `'_` cannot be used here +//[rust2018]~^^ ERROR `'_` cannot be used here +{ } + +fn main() {} diff --git a/src/test/ui/underscore-lifetime/where-clause-trait-impl-underscore.rust2015.stderr b/src/test/ui/underscore-lifetime/where-clause-trait-impl-underscore.rust2015.stderr new file mode 100644 index 0000000000000..92caff0dcde99 --- /dev/null +++ b/src/test/ui/underscore-lifetime/where-clause-trait-impl-underscore.rust2015.stderr @@ -0,0 +1,9 @@ +error[E0637]: `'_` cannot be used here + --> $DIR/where-clause-trait-impl-underscore.rs:11:19 + | +LL | T: WithRegion<'_> + | ^^ `'_` is a reserved lifetime name + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0637`. diff --git a/src/test/ui/underscore-lifetime/where-clause-trait-impl-underscore.rust2018.stderr b/src/test/ui/underscore-lifetime/where-clause-trait-impl-underscore.rust2018.stderr new file mode 100644 index 0000000000000..92caff0dcde99 --- /dev/null +++ b/src/test/ui/underscore-lifetime/where-clause-trait-impl-underscore.rust2018.stderr @@ -0,0 +1,9 @@ +error[E0637]: `'_` cannot be used here + --> $DIR/where-clause-trait-impl-underscore.rs:11:19 + | +LL | T: WithRegion<'_> + | ^^ `'_` is a reserved lifetime name + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0637`. diff --git a/src/test/ui/underscore-lifetime/where-clauses.rs b/src/test/ui/underscore-lifetime/where-clauses.rs new file mode 100644 index 0000000000000..ee6823b804782 --- /dev/null +++ b/src/test/ui/underscore-lifetime/where-clauses.rs @@ -0,0 +1,7 @@ +trait Foo<'a> {} + +impl<'b: '_> Foo<'b> for i32 {} //~ ERROR `'_` cannot be used here + +impl Foo<'static> for Vec {} //~ ERROR `'_` cannot be used here + +fn main() { } diff --git a/src/test/ui/underscore-lifetime/where-clauses.stderr b/src/test/ui/underscore-lifetime/where-clauses.stderr new file mode 100644 index 0000000000000..57fe2456f4cc5 --- /dev/null +++ b/src/test/ui/underscore-lifetime/where-clauses.stderr @@ -0,0 +1,15 @@ +error[E0637]: `'_` cannot be used here + --> $DIR/where-clauses.rs:3:10 + | +LL | impl<'b: '_> Foo<'b> for i32 {} //~ ERROR `'_` cannot be used here + | ^^ `'_` is a reserved lifetime name + +error[E0637]: `'_` cannot be used here + --> $DIR/where-clauses.rs:5:9 + | +LL | impl Foo<'static> for Vec {} //~ ERROR `'_` cannot be used here + | ^^ `'_` is a reserved lifetime name + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0637`.