diff --git a/src/librustc/hir/intravisit.rs b/src/librustc/hir/intravisit.rs index 942f1cbd6651..95b73d5f87b3 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 16e8b8709a81..1fc677b0e292 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,17 +2303,15 @@ 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::Outlives(ref lifetime) => { - // We don't want to accept `'a: '_`: - self.with_anonymous_lifetime_mode( - AnonymousLifetimeMode::PassThrough, - |this| hir::GenericBound::Outlives(this.lower_lifetime(lifetime)), + 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)) + } } } @@ -2323,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); @@ -2361,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, @@ -2494,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 { @@ -4843,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 @@ -4861,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 => {} } @@ -4891,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 c57c26434e32..01b68ae669b6 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 da9604702dfa..fe663c68cd50 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 f51a3e71d074..0c8224710d39 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 2f3fdb7966f2..671604918f7f 100644 --- a/src/librustc/middle/resolve_lifetime.rs +++ b/src/librustc/middle/resolve_lifetime.rs @@ -43,20 +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 + match kind { + LifetimeParamKind::InBand => LifetimeDefOrigin::InBand, + LifetimeParamKind::Explicit => LifetimeDefOrigin::ExplicitOrElided, + LifetimeParamKind::Elided => LifetimeDefOrigin::ExplicitOrElided, + LifetimeParamKind::Error => LifetimeDefOrigin::Error, } } _ => bug!("expected a lifetime param"), @@ -612,6 +615,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) => { @@ -1631,6 +1635,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. @@ -1650,16 +1660,17 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> { } Scope::Binder { ref lifetimes, s, .. } => { - let name = match lifetime_ref.name { - LifetimeName::Param(param_name) => param_name, + 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, .. } => { @@ -1709,8 +1720,10 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> { } 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(..) => {} } @@ -2339,14 +2352,7 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> { 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(); + 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); @@ -2364,6 +2370,9 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> { hir::LifetimeName::Param(_) | hir::LifetimeName::Implicit => { self.resolve_lifetime_ref(lt); } + hir::LifetimeName::Error => { + // No need to do anything, error already reported. + } } _ => bug!(), } diff --git a/src/librustc_lint/builtin.rs b/src/librustc_lint/builtin.rs index d18edf22dc10..bc5f688729c3 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 65ba2f537bf2..ab80eaba6992 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 cc1906d91d4c..713e26754326 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 ee6a978d169a..b4f769a749f8 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 245729376df3..2a4545fc43d0 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 000000000000..a851e6b2071b --- /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 000000000000..77da3038724b --- /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 000000000000..fc0602a0ba96 --- /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 +//[Rust2015]~| ERROR +//[Rust2018]~^^^ ERROR + +struct Struct<'_> { +//[Rust2015]~^ ERROR +//[Rust2018]~^^ ERROR + v: Vec<&'static char> +} + +enum Enum<'_> { +//[Rust2015]~^ ERROR +//[Rust2018]~^^ ERROR + Variant +} + +union Union<'_> { +//[Rust2015]~^ ERROR +//[Rust2018]~^^ ERROR + a: u32 +} + +trait Trait<'_> { +//[Rust2015]~^ ERROR +//[Rust2018]~^^ ERROR +} + +fn foo<'_>() { + //[Rust2015]~^ ERROR + //[Rust2018]~^^ ERROR +} + +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 000000000000..959254b8bb81 --- /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 + +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 000000000000..6536e6b278ed --- /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 + | ^^ 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 000000000000..be605ed50a5c --- /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 +} + +struct Bar { + Variant(&'_ u32), //~ ERROR +} + +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 000000000000..b60b3db408d3 --- /dev/null +++ b/src/test/ui/underscore-lifetime/in-struct.stderr @@ -0,0 +1,15 @@ +error: expected `:`, found `(` + --> $DIR/in-struct.rs:20:12 + | +LL | Variant(&'_ u32), //~ ERROR + | ^ expected `:` + +error[E0106]: missing lifetime specifier + --> $DIR/in-struct.rs:16:9 + | +LL | x: &'_ u32, //~ ERROR + | ^^ 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 6a6698957d9d..2652fc62bb62 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 4917c2795e39..fc9f3e642d40 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 000000000000..b514ff438607 --- /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 000000000000..4b38a26f957f --- /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 000000000000..ee6b35d878e8 --- /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 +//[rust2018]~^^ ERROR +{ } + +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 000000000000..fe726cb49c73 --- /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 000000000000..fe726cb49c73 --- /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 000000000000..55aecbc9fcff --- /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 +//[rust2018]~^^ ERROR +{ } + +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 000000000000..95939fd6b7e0 --- /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 000000000000..95939fd6b7e0 --- /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 000000000000..47de6a7af9c0 --- /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 +//[rust2018]~^^ ERROR +{ } + +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 000000000000..fbd14de21078 --- /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 000000000000..fbd14de21078 --- /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 000000000000..67db6be53618 --- /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 +//[rust2018]~^^ ERROR +{ } + +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 000000000000..92caff0dcde9 --- /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 000000000000..92caff0dcde9 --- /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 000000000000..da91718fec33 --- /dev/null +++ b/src/test/ui/underscore-lifetime/where-clauses.rs @@ -0,0 +1,3 @@ +trait Foo<'a> {} +impl<'b: '_> Foo<'b> for i32 {} +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 000000000000..98ac5b5b3dc4 --- /dev/null +++ b/src/test/ui/underscore-lifetime/where-clauses.stderr @@ -0,0 +1,9 @@ +error[E0637]: `'_` cannot be used here + --> $DIR/where-clauses.rs:2: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`.