From 64314e3ae218cb004735735667581f12df8461ef Mon Sep 17 00:00:00 2001 From: Taylor Cramer Date: Mon, 18 Sep 2017 22:55:21 -0700 Subject: [PATCH] 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 4d21e5e0f47..6e0f49bba90 100644 --- a/src/librustc/diagnostics.rs +++ b/src/librustc/diagnostics.rs @@ -2086,4 +2086,5 @@ fn foo<'a>(x: &'a i32, y: &i32) -> &'a i32 { 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 c250695f361..3d82481807e 100644 --- a/src/librustc/hir/mod.rs +++ b/src/librustc/hir/mod.rs @@ -159,7 +159,8 @@ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 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 2d201e5935e..8b58c75e241 100644 --- a/src/librustc/middle/resolve_lifetime.rs +++ b/src/librustc/middle/resolve_lifetime.rs @@ -1422,7 +1422,7 @@ fn check_lifetime_defs(&mut self, old_scope: ScopeRef, lifetimes: &[hir::Lifetim 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 @@ fn check_lifetime_defs(&mut self, old_scope: ScopeRef, lifetimes: &[hir::Lifetim 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 ffe444933a3..efb5b031809 100644 --- a/src/librustc_passes/ast_validation.rs +++ b/src/librustc_passes/ast_validation.rs @@ -122,14 +122,6 @@ fn check_expr_within_pat(&self, expr: &Expr, allow_paths: bool) { } 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 6560943a932..1fef382c83a 100644 --- a/src/libsyntax/feature_gate.rs +++ b/src/libsyntax/feature_gate.rs @@ -389,6 +389,9 @@ pub fn new() -> 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 @@ fn visit_lifetime_def(&mut self, lifetime_def: &'a ast::LifetimeDef) { } 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 00000000000..455529b088a --- /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 00000000000..9da50c5c877 --- /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 5b518a4931d..30411bf8789 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 00000000000..7d9452249c5 --- /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 00000000000..d3db34a7caa --- /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)); +} -- 2.44.0