From 64314e3ae218cb004735735667581f12df8461ef Mon Sep 17 00:00:00 2001 From: Taylor Cramer Date: Mon, 18 Sep 2017 22:55:21 -0700 Subject: [PATCH 1/4] Implement underscore lifetimes --- src/librustc/diagnostics.rs | 1 + src/librustc/hir/mod.rs | 3 +- src/librustc/middle/resolve_lifetime.rs | 10 ++++-- src/librustc_passes/ast_validation.rs | 8 ----- src/libsyntax/feature_gate.rs | 11 ++++++ src/test/compile-fail/E0637.rs | 20 +++++++++++ .../feature-gate-underscore-lifetimes.rs | 20 +++++++++++ ...time-underscore.rs => label-underscore.rs} | 6 ---- .../underscore-lifetime-binders.rs | 32 +++++++++++++++++ src/test/run-pass/underscore-lifetimes.rs | 35 +++++++++++++++++++ 10 files changed, 129 insertions(+), 17 deletions(-) create mode 100644 src/test/compile-fail/E0637.rs create mode 100644 src/test/compile-fail/feature-gate-underscore-lifetimes.rs rename src/test/compile-fail/{lifetime-underscore.rs => label-underscore.rs} (83%) create mode 100644 src/test/compile-fail/underscore-lifetime-binders.rs create mode 100644 src/test/run-pass/underscore-lifetimes.rs diff --git a/src/librustc/diagnostics.rs b/src/librustc/diagnostics.rs index 4d21e5e0f4708..6e0f49bba90ff 100644 --- a/src/librustc/diagnostics.rs +++ b/src/librustc/diagnostics.rs @@ -2086,4 +2086,5 @@ register_diagnostics! { E0566, // conflicting representation hints E0623, // lifetime mismatch where both parameters are anonymous regions E0628, // generators cannot have explicit arguments + E0637, // "'_" is not a valid lifetime bound } diff --git a/src/librustc/hir/mod.rs b/src/librustc/hir/mod.rs index c250695f361a6..3d82481807e02 100644 --- a/src/librustc/hir/mod.rs +++ b/src/librustc/hir/mod.rs @@ -159,7 +159,8 @@ impl fmt::Debug for Lifetime { impl Lifetime { pub fn is_elided(&self) -> bool { - self.name == keywords::Invalid.name() + self.name == keywords::Invalid.name() || + self.name == "'_" } pub fn is_static(&self) -> bool { diff --git a/src/librustc/middle/resolve_lifetime.rs b/src/librustc/middle/resolve_lifetime.rs index 2d201e5935ec7..8b58c75e2418e 100644 --- a/src/librustc/middle/resolve_lifetime.rs +++ b/src/librustc/middle/resolve_lifetime.rs @@ -1422,7 +1422,7 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> { let lifetime_i = &lifetimes[i]; for lifetime in lifetimes { - if lifetime.lifetime.is_static() { + if lifetime.lifetime.is_static() || lifetime.lifetime.name == "'_" { let lifetime = lifetime.lifetime; let mut err = struct_span_err!(self.sess, lifetime.span, E0262, "invalid lifetime parameter name: `{}`", lifetime.name); @@ -1452,7 +1452,13 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> { self.check_lifetime_def_for_shadowing(old_scope, &lifetime_i.lifetime); for bound in &lifetime_i.bounds { - if !bound.is_static() { + if bound.name == "'_" { + let mut err = struct_span_err!(self.sess, bound.span, E0637, + "invalid lifetime bound name: `{}`", bound.name); + err.span_label(bound.span, + format!("{} is a reserved lifetime name", bound.name)); + err.emit(); + } else if !bound.is_static() { self.resolve_lifetime_ref(bound); } else { self.insert_lifetime(bound, Region::Static); diff --git a/src/librustc_passes/ast_validation.rs b/src/librustc_passes/ast_validation.rs index ffe444933a3b1..efb5b03180998 100644 --- a/src/librustc_passes/ast_validation.rs +++ b/src/librustc_passes/ast_validation.rs @@ -122,14 +122,6 @@ impl<'a> AstValidator<'a> { } impl<'a> Visitor<'a> for AstValidator<'a> { - fn visit_lifetime(&mut self, lt: &'a Lifetime) { - if lt.ident.name == "'_" { - self.err_handler().span_err(lt.span, &format!("invalid lifetime name `{}`", lt.ident)); - } - - visit::walk_lifetime(self, lt) - } - fn visit_expr(&mut self, expr: &'a Expr) { match expr.node { ExprKind::While(.., Some(ident)) | diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs index 6560943a9328b..1fef382c83a34 100644 --- a/src/libsyntax/feature_gate.rs +++ b/src/libsyntax/feature_gate.rs @@ -389,6 +389,9 @@ declare_features! ( // Copy/Clone closures (RFC 2132) (active, clone_closures, "1.22.0", Some(44490)), (active, copy_closures, "1.22.0", Some(44490)), + + // allow `'_` placeholder lifetimes + (active, underscore_lifetimes, "1.22.0", Some(44524)), ); declare_features! ( @@ -1572,6 +1575,14 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> { } visit::walk_lifetime_def(self, lifetime_def) } + + fn visit_lifetime(&mut self, lt: &'a ast::Lifetime) { + if lt.ident.name == "'_" { + gate_feature_post!(&self, underscore_lifetimes, lt.span, + "underscore lifetimes are unstable"); + } + visit::walk_lifetime(self, lt) + } } pub fn get_features(span_handler: &Handler, krate_attrs: &[ast::Attribute]) -> Features { diff --git a/src/test/compile-fail/E0637.rs b/src/test/compile-fail/E0637.rs new file mode 100644 index 0000000000000..455529b088a2e --- /dev/null +++ b/src/test/compile-fail/E0637.rs @@ -0,0 +1,20 @@ +// Copyright 2017 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. +#![feature(underscore_lifetimes)] + +struct Foo<'a: '_>(&'a u8); //~ ERROR invalid lifetime bound name: `'_` +fn foo<'a: '_>(_: &'a u8) {} //~ ERROR invalid lifetime bound name: `'_` + +struct Bar<'a>(&'a u8); +impl<'a: '_> Bar<'a> { //~ ERROR invalid lifetime bound name: `'_` + fn bar() {} +} + +fn main() {} diff --git a/src/test/compile-fail/feature-gate-underscore-lifetimes.rs b/src/test/compile-fail/feature-gate-underscore-lifetimes.rs new file mode 100644 index 0000000000000..9da50c5c87719 --- /dev/null +++ b/src/test/compile-fail/feature-gate-underscore-lifetimes.rs @@ -0,0 +1,20 @@ +// Copyright 2017 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. + +struct Foo<'a>(&'a u8); + +fn foo(x: &u8) -> Foo<'_> { //~ ERROR underscore lifetimes are unstable + Foo(x) +} + +fn main() { + let x = 5; + let _ = foo(&x); +} diff --git a/src/test/compile-fail/lifetime-underscore.rs b/src/test/compile-fail/label-underscore.rs similarity index 83% rename from src/test/compile-fail/lifetime-underscore.rs rename to src/test/compile-fail/label-underscore.rs index 5b518a4931da8..30411bf878909 100644 --- a/src/test/compile-fail/lifetime-underscore.rs +++ b/src/test/compile-fail/label-underscore.rs @@ -8,12 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -fn _f<'_>() //~ ERROR invalid lifetime name `'_` - -> &'_ u8 //~ ERROR invalid lifetime name `'_` -{ - panic!(); -} - fn main() { '_: loop { //~ ERROR invalid label name `'_` break '_ //~ ERROR invalid label name `'_` diff --git a/src/test/compile-fail/underscore-lifetime-binders.rs b/src/test/compile-fail/underscore-lifetime-binders.rs new file mode 100644 index 0000000000000..7d9452249c5ce --- /dev/null +++ b/src/test/compile-fail/underscore-lifetime-binders.rs @@ -0,0 +1,32 @@ +// Copyright 2017 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. + +#![feature(underscore_lifetimes)] + +struct Foo<'a>(&'a u8); + +fn foo<'_> //~ ERROR invalid lifetime parameter name: `'_` +(_: Foo<'_>) {} + +trait Meh<'a> {} +impl<'a> Meh<'a> for u8 {} + +fn meh() -> Box Meh<'_>> //~ ERROR invalid lifetime parameter name: `'_` +//~^ ERROR missing lifetime specifier +//~^^ ERROR missing lifetime specifier +{ + Box::new(5u8) +} + +fn main() { + let x = 5; + foo(Foo(&x)); + let _ = meh(); +} diff --git a/src/test/run-pass/underscore-lifetimes.rs b/src/test/run-pass/underscore-lifetimes.rs new file mode 100644 index 0000000000000..d3db34a7caa97 --- /dev/null +++ b/src/test/run-pass/underscore-lifetimes.rs @@ -0,0 +1,35 @@ +// Copyright 2017 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. + +#![feature(underscore_lifetimes)] + +struct Foo<'a>(&'a u8); + +fn foo(x: &u8) -> Foo<'_> { + Foo(x) +} + +fn foo2(x: &'_ u8) -> Foo<'_> { + Foo(x) +} + +fn foo3(x: &'_ u8) -> Foo { + Foo(x) +} + +fn foo4(_: Foo<'_>) {} + +fn main() { + let x = &5; + let _ = foo(x); + let _ = foo2(x); + let _ = foo3(x); + foo4(Foo(x)); +} From f64af7a32e83ae6c02a0e0378c024e687fec5223 Mon Sep 17 00:00:00 2001 From: Taylor Cramer Date: Tue, 19 Sep 2017 16:36:54 -0700 Subject: [PATCH 2/4] Refactor lifetime name into an enum --- src/librustc/hir/intravisit.rs | 7 +- src/librustc/hir/lowering.rs | 8 ++- src/librustc/hir/map/mod.rs | 2 +- src/librustc/hir/mod.rs | 31 +++++++-- src/librustc/hir/print.rs | 2 +- src/librustc/ich/impls_hir.rs | 7 ++ src/librustc/middle/resolve_lifetime.rs | 84 +++++++++++++---------- src/librustc_lint/bad_style.rs | 2 +- src/librustc_typeck/check/wfcheck.rs | 2 +- src/librustc_typeck/collect.rs | 4 +- src/librustc_typeck/impl_wf_check.rs | 2 +- src/librustdoc/clean/mod.rs | 10 +-- src/test/run-pass/underscore-lifetimes.rs | 12 ++++ 13 files changed, 118 insertions(+), 55 deletions(-) diff --git a/src/librustc/hir/intravisit.rs b/src/librustc/hir/intravisit.rs index 9d8075de2eb2f..088fd8d90901c 100644 --- a/src/librustc/hir/intravisit.rs +++ b/src/librustc/hir/intravisit.rs @@ -422,7 +422,12 @@ pub fn walk_local<'v, V: Visitor<'v>>(visitor: &mut V, local: &'v Local) { pub fn walk_lifetime<'v, V: Visitor<'v>>(visitor: &mut V, lifetime: &'v Lifetime) { visitor.visit_id(lifetime.id); - visitor.visit_name(lifetime.span, lifetime.name); + match lifetime.name { + LifetimeName::Name(name) => { + visitor.visit_name(lifetime.span, name); + } + LifetimeName::Static | LifetimeName::Implicit | LifetimeName::Underscore => {} + } } pub fn walk_lifetime_def<'v, V: Visitor<'v>>(visitor: &mut V, lifetime_def: &'v LifetimeDef) { diff --git a/src/librustc/hir/lowering.rs b/src/librustc/hir/lowering.rs index c7ea9c4702869..465520ea03434 100644 --- a/src/librustc/hir/lowering.rs +++ b/src/librustc/hir/lowering.rs @@ -1121,7 +1121,11 @@ impl<'a> LoweringContext<'a> { fn lower_lifetime(&mut self, l: &Lifetime) -> hir::Lifetime { hir::Lifetime { id: self.lower_node_id(l.id).node_id, - name: self.lower_ident(l.ident), + name: match self.lower_ident(l.ident) { + x if x == "'_" => hir::LifetimeName::Underscore, + x if x == "'static" => hir::LifetimeName::Static, + name => hir::LifetimeName::Name(name), + }, span: l.span, } } @@ -3005,7 +3009,7 @@ impl<'a> LoweringContext<'a> { hir::Lifetime { id: self.next_id().node_id, span, - name: keywords::Invalid.name() + name: hir::LifetimeName::Implicit, } } } diff --git a/src/librustc/hir/map/mod.rs b/src/librustc/hir/map/mod.rs index b2d6886e7f228..c0577039f0c35 100644 --- a/src/librustc/hir/map/mod.rs +++ b/src/librustc/hir/map/mod.rs @@ -805,7 +805,7 @@ impl<'hir> Map<'hir> { NodeTraitItem(ti) => ti.name, NodeVariant(v) => v.node.name, NodeField(f) => f.name, - NodeLifetime(lt) => lt.name, + NodeLifetime(lt) => lt.name.name(), NodeTyParam(tp) => tp.name, NodeBinding(&Pat { node: PatKind::Binding(_,_,l,_), .. }) => l.node, NodeStructCtor(_) => self.name(self.get_parent(id)), diff --git a/src/librustc/hir/mod.rs b/src/librustc/hir/mod.rs index 3d82481807e02..1bef17b28acb5 100644 --- a/src/librustc/hir/mod.rs +++ b/src/librustc/hir/mod.rs @@ -145,7 +145,27 @@ pub struct Lifetime { /// HIR lowering inserts these placeholders in type paths that /// refer to type definitions needing lifetime parameters, /// `&T` and `&mut T`, and trait objects without `... + 'a`. - pub name: Name, + pub name: LifetimeName, +} + +#[derive(Debug, Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Copy)] +pub enum LifetimeName { + Implicit, + Underscore, + Static, + Name(Name), +} + +impl LifetimeName { + pub fn name(&self) -> Name { + use self::LifetimeName::*; + match *self { + Implicit => keywords::Invalid.name(), + Underscore => Symbol::intern("'_"), + Static => keywords::StaticLifetime.name(), + Name(name) => name, + } + } } impl fmt::Debug for Lifetime { @@ -159,12 +179,15 @@ impl fmt::Debug for Lifetime { impl Lifetime { pub fn is_elided(&self) -> bool { - self.name == keywords::Invalid.name() || - self.name == "'_" + use self::LifetimeName::*; + match self.name { + Implicit | Underscore => true, + Static | Name(_) => false, + } } pub fn is_static(&self) -> bool { - self.name == "'static" + self.name == LifetimeName::Static } } diff --git a/src/librustc/hir/print.rs b/src/librustc/hir/print.rs index 41a253f7904f7..ad31b2009a01d 100644 --- a/src/librustc/hir/print.rs +++ b/src/librustc/hir/print.rs @@ -1975,7 +1975,7 @@ impl<'a> State<'a> { } pub fn print_lifetime(&mut self, lifetime: &hir::Lifetime) -> io::Result<()> { - self.print_name(lifetime.name) + self.print_name(lifetime.name.name()) } pub fn print_lifetime_def(&mut self, lifetime: &hir::LifetimeDef) -> io::Result<()> { diff --git a/src/librustc/ich/impls_hir.rs b/src/librustc/ich/impls_hir.rs index 9582b03ce1c8a..b3af44c952bdd 100644 --- a/src/librustc/ich/impls_hir.rs +++ b/src/librustc/ich/impls_hir.rs @@ -123,6 +123,13 @@ impl<'gcx> HashStable> for hir::ImplItemId { } } +impl_stable_hash_for!(enum hir::LifetimeName { + Implicit, + Underscore, + Static, + Name(name) +}); + impl_stable_hash_for!(struct hir::Lifetime { id, span, diff --git a/src/librustc/middle/resolve_lifetime.rs b/src/librustc/middle/resolve_lifetime.rs index 8b58c75e2418e..60f03eb5d89ec 100644 --- a/src/librustc/middle/resolve_lifetime.rs +++ b/src/librustc/middle/resolve_lifetime.rs @@ -46,14 +46,16 @@ pub enum Region { } impl Region { - fn early(hir_map: &Map, index: &mut u32, def: &hir::LifetimeDef) -> (ast::Name, Region) { + fn early(hir_map: &Map, index: &mut u32, def: &hir::LifetimeDef) + -> (hir::LifetimeName, Region) + { let i = *index; *index += 1; let def_id = hir_map.local_def_id(def.lifetime.id); (def.lifetime.name, Region::EarlyBound(i, def_id)) } - fn late(hir_map: &Map, def: &hir::LifetimeDef) -> (ast::Name, Region) { + fn late(hir_map: &Map, def: &hir::LifetimeDef) -> (hir::LifetimeName, Region) { let depth = ty::DebruijnIndex::new(1); let def_id = hir_map.local_def_id(def.lifetime.id); (def.lifetime.name, Region::LateBound(depth, def_id)) @@ -198,7 +200,7 @@ enum Scope<'a> { /// it should be shifted by the number of `Binder`s in between the /// declaration `Binder` and the location it's referenced from. Binder { - lifetimes: FxHashMap, + lifetimes: FxHashMap, s: ScopeRef<'a> }, @@ -654,7 +656,7 @@ fn extract_labels(ctxt: &mut LifetimeContext, body: &hir::Body) { Scope::Binder { ref lifetimes, s } => { // FIXME (#24278): non-hygienic comparison - if let Some(def) = lifetimes.get(&label) { + if let Some(def) = lifetimes.get(&hir::LifetimeName::Name(label)) { let node_id = hir_map.as_local_node_id(def.id().unwrap()) .unwrap(); @@ -692,7 +694,7 @@ fn compute_object_lifetime_defaults(sess: &Session, hir_map: &Map) Set1::Empty => "BaseDefault".to_string(), Set1::One(Region::Static) => "'static".to_string(), Set1::One(Region::EarlyBound(i, _)) => { - generics.lifetimes[i as usize].lifetime.name.to_string() + generics.lifetimes[i as usize].lifetime.name.name().to_string() } Set1::One(_) => bug!(), Set1::Many => "Ambiguous".to_string(), @@ -714,7 +716,7 @@ fn compute_object_lifetime_defaults(sess: &Session, hir_map: &Map) /// for each type parameter. fn object_lifetime_defaults_for_item(hir_map: &Map, generics: &hir::Generics) -> Vec { - fn add_bounds(set: &mut Set1, bounds: &[hir::TyParamBound]) { + fn add_bounds(set: &mut Set1, bounds: &[hir::TyParamBound]) { for bound in bounds { if let hir::RegionTyParamBound(ref lifetime) = *bound { set.insert(lifetime.name); @@ -754,7 +756,7 @@ fn object_lifetime_defaults_for_item(hir_map: &Map, generics: &hir::Generics) match set { Set1::Empty => Set1::Empty, Set1::One(name) => { - if name == "'static" { + if name == hir::LifetimeName::Static { Set1::One(Region::Static) } else { generics.lifetimes.iter().enumerate().find(|&(_, def)| { @@ -922,7 +924,7 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> { self.insert_lifetime(lifetime_ref, def); } else { struct_span_err!(self.sess, lifetime_ref.span, E0261, - "use of undeclared lifetime name `{}`", lifetime_ref.name) + "use of undeclared lifetime name `{}`", lifetime_ref.name.name()) .span_label(lifetime_ref.span, "undeclared lifetime") .emit(); } @@ -1422,13 +1424,17 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> { let lifetime_i = &lifetimes[i]; for lifetime in lifetimes { - if lifetime.lifetime.is_static() || lifetime.lifetime.name == "'_" { - let lifetime = lifetime.lifetime; - let mut err = struct_span_err!(self.sess, lifetime.span, E0262, - "invalid lifetime parameter name: `{}`", lifetime.name); - err.span_label(lifetime.span, - format!("{} is a reserved lifetime name", lifetime.name)); - err.emit(); + match lifetime.lifetime.name { + hir::LifetimeName::Static | hir::LifetimeName::Underscore => { + let lifetime = lifetime.lifetime; + let name = lifetime.name.name(); + let mut err = struct_span_err!(self.sess, lifetime.span, E0262, + "invalid lifetime parameter name: `{}`", name); + err.span_label(lifetime.span, + format!("{} is a reserved lifetime name", name)); + err.emit(); + } + hir::LifetimeName::Implicit | hir::LifetimeName::Name(_) => {} } } @@ -1439,7 +1445,7 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> { if lifetime_i.lifetime.name == lifetime_j.lifetime.name { struct_span_err!(self.sess, lifetime_j.lifetime.span, E0263, "lifetime name `{}` declared twice in the same scope", - lifetime_j.lifetime.name) + lifetime_j.lifetime.name.name()) .span_label(lifetime_j.lifetime.span, "declared twice") .span_label(lifetime_i.lifetime.span, @@ -1452,21 +1458,27 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> { self.check_lifetime_def_for_shadowing(old_scope, &lifetime_i.lifetime); for bound in &lifetime_i.bounds { - if bound.name == "'_" { - let mut err = struct_span_err!(self.sess, bound.span, E0637, - "invalid lifetime bound name: `{}`", bound.name); - err.span_label(bound.span, - format!("{} is a reserved lifetime name", bound.name)); - err.emit(); - } else if !bound.is_static() { - self.resolve_lifetime_ref(bound); - } else { - self.insert_lifetime(bound, Region::Static); - self.sess.struct_span_warn(lifetime_i.lifetime.span.to(bound.span), - &format!("unnecessary lifetime parameter `{}`", lifetime_i.lifetime.name)) - .help(&format!("you can use the `'static` lifetime directly, in place \ - of `{}`", lifetime_i.lifetime.name)) - .emit(); + match bound.name { + hir::LifetimeName::Underscore => { + let mut err = struct_span_err!(self.sess, bound.span, E0637, + "invalid lifetime bound name: `'_`"); + err.span_label(bound.span, "`'_` is a reserved lifetime name"); + err.emit(); + } + hir::LifetimeName::Static => { + self.insert_lifetime(bound, Region::Static); + self.sess.struct_span_warn(lifetime_i.lifetime.span.to(bound.span), + &format!("unnecessary lifetime parameter `{}`", + lifetime_i.lifetime.name.name())) + .help(&format!( + "you can use the `'static` lifetime directly, in place \ + of `{}`", lifetime_i.lifetime.name.name())) + .emit(); + } + hir::LifetimeName::Implicit | + hir::LifetimeName::Name(_) => { + self.resolve_lifetime_ref(bound); + } } } } @@ -1478,9 +1490,9 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> { { for &(label, label_span) in &self.labels_in_fn { // FIXME (#24278): non-hygienic comparison - if lifetime.name == label { + if lifetime.name.name() == label { signal_shadowing_problem(self.sess, - lifetime.name, + label, original_label(label_span), shadower_lifetime(&lifetime)); return; @@ -1507,7 +1519,7 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> { signal_shadowing_problem( self.sess, - lifetime.name, + lifetime.name.name(), original_lifetime(self.hir_map.span(node_id)), shadower_lifetime(&lifetime)); return; @@ -1623,7 +1635,7 @@ fn insert_late_bound_lifetimes(map: &mut NamedRegionMap, return; struct ConstrainedCollector { - regions: FxHashSet, + regions: FxHashSet, } impl<'v> Visitor<'v> for ConstrainedCollector { @@ -1663,7 +1675,7 @@ fn insert_late_bound_lifetimes(map: &mut NamedRegionMap, } struct AllCollector { - regions: FxHashSet, + regions: FxHashSet, impl_trait: bool } diff --git a/src/librustc_lint/bad_style.rs b/src/librustc_lint/bad_style.rs index d4b8f0a492461..cbc012a65faad 100644 --- a/src/librustc_lint/bad_style.rs +++ b/src/librustc_lint/bad_style.rs @@ -278,7 +278,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for NonSnakeCase { fn check_lifetime_def(&mut self, cx: &LateContext, t: &hir::LifetimeDef) { self.check_snake_case(cx, "lifetime", - &t.lifetime.name.as_str(), + &t.lifetime.name.name().as_str(), Some(t.lifetime.span)); } diff --git a/src/librustc_typeck/check/wfcheck.rs b/src/librustc_typeck/check/wfcheck.rs index f17df8b22f393..ddbdd20430589 100644 --- a/src/librustc_typeck/check/wfcheck.rs +++ b/src/librustc_typeck/check/wfcheck.rs @@ -523,7 +523,7 @@ impl<'a, 'gcx> CheckTypeWellFormedVisitor<'a, 'gcx> { let (span, name) = if index < ast_generics.lifetimes.len() { (ast_generics.lifetimes[index].lifetime.span, - ast_generics.lifetimes[index].lifetime.name) + ast_generics.lifetimes[index].lifetime.name.name()) } else { let index = index - ast_generics.lifetimes.len(); (ast_generics.ty_params[index].span, diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs index 79cb9147c185b..8d078b9227512 100644 --- a/src/librustc_typeck/collect.rs +++ b/src/librustc_typeck/collect.rs @@ -953,7 +953,7 @@ fn generics_of<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, let early_lifetimes = early_bound_lifetimes_from_generics(tcx, ast_generics); let regions = early_lifetimes.enumerate().map(|(i, l)| { ty::RegionParameterDef { - name: l.lifetime.name, + name: l.lifetime.name.name(), index: own_start + i as u32, def_id: tcx.hir.local_def_id(l.lifetime.id), pure_wrt_drop: l.pure_wrt_drop, @@ -1423,7 +1423,7 @@ fn predicates_of<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, let region = tcx.mk_region(ty::ReEarlyBound(ty::EarlyBoundRegion { def_id: tcx.hir.local_def_id(param.lifetime.id), index, - name: param.lifetime.name + name: param.lifetime.name.name(), })); index += 1; diff --git a/src/librustc_typeck/impl_wf_check.rs b/src/librustc_typeck/impl_wf_check.rs index 14e48b9302964..15708ab766ae8 100644 --- a/src/librustc_typeck/impl_wf_check.rs +++ b/src/librustc_typeck/impl_wf_check.rs @@ -132,7 +132,7 @@ fn enforce_impl_params_are_constrained<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, !input_parameters.contains(¶m) { report_unused_parameter(tcx, lifetime.lifetime.span, - "lifetime", &lifetime.lifetime.name.to_string()); + "lifetime", &lifetime.lifetime.name.name().to_string()); } } diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index 095eb7797d457..1e25a57b1d2b1 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -876,7 +876,7 @@ impl Clean for hir::Lifetime { } _ => {} } - Lifetime(self.name.to_string()) + Lifetime(self.name.name().to_string()) } } @@ -884,14 +884,14 @@ impl Clean for hir::LifetimeDef { fn clean(&self, _: &DocContext) -> Lifetime { if self.bounds.len() > 0 { let mut s = format!("{}: {}", - self.lifetime.name.to_string(), - self.bounds[0].name.to_string()); + self.lifetime.name.name(), + self.bounds[0].name.name()); for bound in self.bounds.iter().skip(1) { - s.push_str(&format!(" + {}", bound.name.to_string())); + s.push_str(&format!(" + {}", bound.name.name())); } Lifetime(s) } else { - Lifetime(self.lifetime.name.to_string()) + Lifetime(self.lifetime.name.name().to_string()) } } } diff --git a/src/test/run-pass/underscore-lifetimes.rs b/src/test/run-pass/underscore-lifetimes.rs index d3db34a7caa97..ed0369353bcd3 100644 --- a/src/test/run-pass/underscore-lifetimes.rs +++ b/src/test/run-pass/underscore-lifetimes.rs @@ -26,10 +26,22 @@ fn foo3(x: &'_ u8) -> Foo { fn foo4(_: Foo<'_>) {} +struct Foo2<'a, 'b> { + a: &'a u8, + b: &'b u8, +} +fn foo5<'b>(foo: Foo2<'_, 'b>) -> &'b u8 { + foo.b +} + fn main() { let x = &5; let _ = foo(x); let _ = foo2(x); let _ = foo3(x); foo4(Foo(x)); + let _ = foo5(Foo2 { + a: x, + b: &6, + }); } From 06926b6298693a1fd6ad85073fc38b26cf6d6fbf Mon Sep 17 00:00:00 2001 From: Taylor Cramer Date: Tue, 19 Sep 2017 16:43:18 -0700 Subject: [PATCH 3/4] Add tests for multiple underscore and non-underscore lifetimes --- .../compile-fail/underscore-lifetime-binders.rs | 2 ++ .../underscore-lifetime-elison-mismatch.rs | 15 +++++++++++++++ 2 files changed, 17 insertions(+) create mode 100644 src/test/compile-fail/underscore-lifetime-elison-mismatch.rs diff --git a/src/test/compile-fail/underscore-lifetime-binders.rs b/src/test/compile-fail/underscore-lifetime-binders.rs index 7d9452249c5ce..57cabc81778eb 100644 --- a/src/test/compile-fail/underscore-lifetime-binders.rs +++ b/src/test/compile-fail/underscore-lifetime-binders.rs @@ -25,6 +25,8 @@ fn meh() -> Box Meh<'_>> //~ ERROR invalid lifetime parameter name: `'_` Box::new(5u8) } +fn foo2(_: &'_ u8, y: &'_ u8) -> &'_ u8 { y } //~ ERROR missing lifetime specifier + fn main() { let x = 5; foo(Foo(&x)); diff --git a/src/test/compile-fail/underscore-lifetime-elison-mismatch.rs b/src/test/compile-fail/underscore-lifetime-elison-mismatch.rs new file mode 100644 index 0000000000000..a1c4e4a1fd935 --- /dev/null +++ b/src/test/compile-fail/underscore-lifetime-elison-mismatch.rs @@ -0,0 +1,15 @@ +// Copyright 2017 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. + +#![feature(underscore_lifetimes)] + +fn foo(x: &mut Vec<&'_ u8>, y: &'_ u8) { x.push(y); } //~ ERROR lifetime mismatch + +fn main() {} From f5505d185ccb9b1d84e6d7cdab20f901a778a86c Mon Sep 17 00:00:00 2001 From: Taylor Cramer Date: Wed, 20 Sep 2017 16:06:08 -0700 Subject: [PATCH 4/4] Add tests for underscore lifetimes in impl headers and struct definitions --- src/test/compile-fail/underscore-lifetime-binders.rs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/test/compile-fail/underscore-lifetime-binders.rs b/src/test/compile-fail/underscore-lifetime-binders.rs index 57cabc81778eb..99b6e036f33ea 100644 --- a/src/test/compile-fail/underscore-lifetime-binders.rs +++ b/src/test/compile-fail/underscore-lifetime-binders.rs @@ -11,6 +11,11 @@ #![feature(underscore_lifetimes)] struct Foo<'a>(&'a u8); +struct Baz<'a>(&'_ &'a u8); //~ ERROR missing lifetime specifier + +impl Foo<'_> { //~ ERROR missing lifetime specifier + fn x() {} +} fn foo<'_> //~ ERROR invalid lifetime parameter name: `'_` (_: Foo<'_>) {}