Skip to content

Commit 64314e3

Browse files
committed
Implement underscore lifetimes
1 parent e2504cf commit 64314e3

File tree

10 files changed

+129
-17
lines changed

10 files changed

+129
-17
lines changed

src/librustc/diagnostics.rs

+1
Original file line numberDiff line numberDiff line change
@@ -2086,4 +2086,5 @@ register_diagnostics! {
20862086
E0566, // conflicting representation hints
20872087
E0623, // lifetime mismatch where both parameters are anonymous regions
20882088
E0628, // generators cannot have explicit arguments
2089+
E0637, // "'_" is not a valid lifetime bound
20892090
}

src/librustc/hir/mod.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -159,7 +159,8 @@ impl fmt::Debug for Lifetime {
159159

160160
impl Lifetime {
161161
pub fn is_elided(&self) -> bool {
162-
self.name == keywords::Invalid.name()
162+
self.name == keywords::Invalid.name() ||
163+
self.name == "'_"
163164
}
164165

165166
pub fn is_static(&self) -> bool {

src/librustc/middle/resolve_lifetime.rs

+8-2
Original file line numberDiff line numberDiff line change
@@ -1422,7 +1422,7 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
14221422
let lifetime_i = &lifetimes[i];
14231423

14241424
for lifetime in lifetimes {
1425-
if lifetime.lifetime.is_static() {
1425+
if lifetime.lifetime.is_static() || lifetime.lifetime.name == "'_" {
14261426
let lifetime = lifetime.lifetime;
14271427
let mut err = struct_span_err!(self.sess, lifetime.span, E0262,
14281428
"invalid lifetime parameter name: `{}`", lifetime.name);
@@ -1452,7 +1452,13 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
14521452
self.check_lifetime_def_for_shadowing(old_scope, &lifetime_i.lifetime);
14531453

14541454
for bound in &lifetime_i.bounds {
1455-
if !bound.is_static() {
1455+
if bound.name == "'_" {
1456+
let mut err = struct_span_err!(self.sess, bound.span, E0637,
1457+
"invalid lifetime bound name: `{}`", bound.name);
1458+
err.span_label(bound.span,
1459+
format!("{} is a reserved lifetime name", bound.name));
1460+
err.emit();
1461+
} else if !bound.is_static() {
14561462
self.resolve_lifetime_ref(bound);
14571463
} else {
14581464
self.insert_lifetime(bound, Region::Static);

src/librustc_passes/ast_validation.rs

-8
Original file line numberDiff line numberDiff line change
@@ -122,14 +122,6 @@ impl<'a> AstValidator<'a> {
122122
}
123123

124124
impl<'a> Visitor<'a> for AstValidator<'a> {
125-
fn visit_lifetime(&mut self, lt: &'a Lifetime) {
126-
if lt.ident.name == "'_" {
127-
self.err_handler().span_err(lt.span, &format!("invalid lifetime name `{}`", lt.ident));
128-
}
129-
130-
visit::walk_lifetime(self, lt)
131-
}
132-
133125
fn visit_expr(&mut self, expr: &'a Expr) {
134126
match expr.node {
135127
ExprKind::While(.., Some(ident)) |

src/libsyntax/feature_gate.rs

+11
Original file line numberDiff line numberDiff line change
@@ -389,6 +389,9 @@ declare_features! (
389389
// Copy/Clone closures (RFC 2132)
390390
(active, clone_closures, "1.22.0", Some(44490)),
391391
(active, copy_closures, "1.22.0", Some(44490)),
392+
393+
// allow `'_` placeholder lifetimes
394+
(active, underscore_lifetimes, "1.22.0", Some(44524)),
392395
);
393396

394397
declare_features! (
@@ -1572,6 +1575,14 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> {
15721575
}
15731576
visit::walk_lifetime_def(self, lifetime_def)
15741577
}
1578+
1579+
fn visit_lifetime(&mut self, lt: &'a ast::Lifetime) {
1580+
if lt.ident.name == "'_" {
1581+
gate_feature_post!(&self, underscore_lifetimes, lt.span,
1582+
"underscore lifetimes are unstable");
1583+
}
1584+
visit::walk_lifetime(self, lt)
1585+
}
15751586
}
15761587

15771588
pub fn get_features(span_handler: &Handler, krate_attrs: &[ast::Attribute]) -> Features {

src/test/compile-fail/E0637.rs

+20
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
#![feature(underscore_lifetimes)]
11+
12+
struct Foo<'a: '_>(&'a u8); //~ ERROR invalid lifetime bound name: `'_`
13+
fn foo<'a: '_>(_: &'a u8) {} //~ ERROR invalid lifetime bound name: `'_`
14+
15+
struct Bar<'a>(&'a u8);
16+
impl<'a: '_> Bar<'a> { //~ ERROR invalid lifetime bound name: `'_`
17+
fn bar() {}
18+
}
19+
20+
fn main() {}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
struct Foo<'a>(&'a u8);
12+
13+
fn foo(x: &u8) -> Foo<'_> { //~ ERROR underscore lifetimes are unstable
14+
Foo(x)
15+
}
16+
17+
fn main() {
18+
let x = 5;
19+
let _ = foo(&x);
20+
}

src/test/compile-fail/lifetime-underscore.rs renamed to src/test/compile-fail/label-underscore.rs

-6
Original file line numberDiff line numberDiff line change
@@ -8,12 +8,6 @@
88
// option. This file may not be copied, modified, or distributed
99
// except according to those terms.
1010

11-
fn _f<'_>() //~ ERROR invalid lifetime name `'_`
12-
-> &'_ u8 //~ ERROR invalid lifetime name `'_`
13-
{
14-
panic!();
15-
}
16-
1711
fn main() {
1812
'_: loop { //~ ERROR invalid label name `'_`
1913
break '_ //~ ERROR invalid label name `'_`
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
#![feature(underscore_lifetimes)]
12+
13+
struct Foo<'a>(&'a u8);
14+
15+
fn foo<'_> //~ ERROR invalid lifetime parameter name: `'_`
16+
(_: Foo<'_>) {}
17+
18+
trait Meh<'a> {}
19+
impl<'a> Meh<'a> for u8 {}
20+
21+
fn meh() -> Box<for<'_> Meh<'_>> //~ ERROR invalid lifetime parameter name: `'_`
22+
//~^ ERROR missing lifetime specifier
23+
//~^^ ERROR missing lifetime specifier
24+
{
25+
Box::new(5u8)
26+
}
27+
28+
fn main() {
29+
let x = 5;
30+
foo(Foo(&x));
31+
let _ = meh();
32+
}
+35
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
#![feature(underscore_lifetimes)]
12+
13+
struct Foo<'a>(&'a u8);
14+
15+
fn foo(x: &u8) -> Foo<'_> {
16+
Foo(x)
17+
}
18+
19+
fn foo2(x: &'_ u8) -> Foo<'_> {
20+
Foo(x)
21+
}
22+
23+
fn foo3(x: &'_ u8) -> Foo {
24+
Foo(x)
25+
}
26+
27+
fn foo4(_: Foo<'_>) {}
28+
29+
fn main() {
30+
let x = &5;
31+
let _ = foo(x);
32+
let _ = foo2(x);
33+
let _ = foo3(x);
34+
foo4(Foo(x));
35+
}

0 commit comments

Comments
 (0)