mirror of
https://github.com/rust-lang/rust.git
synced 2025-01-26 22:53:28 +00:00
Auto merge of #44691 - cramertj:underscore-lifetimes, r=nikomatsakis
Implement underscore lifetimes Part of https://github.com/rust-lang/rust/issues/44524
This commit is contained in:
commit
3eb19bf9b1
@ -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
|
||||
}
|
||||
|
@ -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) {
|
||||
|
@ -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,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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)),
|
||||
|
@ -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,11 +179,15 @@ impl fmt::Debug for Lifetime {
|
||||
|
||||
impl Lifetime {
|
||||
pub fn is_elided(&self) -> bool {
|
||||
self.name == keywords::Invalid.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
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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<()> {
|
||||
|
@ -123,6 +123,13 @@ impl<'gcx> HashStable<StableHashingContext<'gcx>> for hir::ImplItemId {
|
||||
}
|
||||
}
|
||||
|
||||
impl_stable_hash_for!(enum hir::LifetimeName {
|
||||
Implicit,
|
||||
Underscore,
|
||||
Static,
|
||||
Name(name)
|
||||
});
|
||||
|
||||
impl_stable_hash_for!(struct hir::Lifetime {
|
||||
id,
|
||||
span,
|
||||
|
@ -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<ast::Name, Region>,
|
||||
lifetimes: FxHashMap<hir::LifetimeName, Region>,
|
||||
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<ObjectLifetimeDefault> {
|
||||
fn add_bounds(set: &mut Set1<ast::Name>, bounds: &[hir::TyParamBound]) {
|
||||
fn add_bounds(set: &mut Set1<hir::LifetimeName>, 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() {
|
||||
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,15 +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.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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1472,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;
|
||||
@ -1501,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;
|
||||
@ -1617,7 +1635,7 @@ fn insert_late_bound_lifetimes(map: &mut NamedRegionMap,
|
||||
return;
|
||||
|
||||
struct ConstrainedCollector {
|
||||
regions: FxHashSet<ast::Name>,
|
||||
regions: FxHashSet<hir::LifetimeName>,
|
||||
}
|
||||
|
||||
impl<'v> Visitor<'v> for ConstrainedCollector {
|
||||
@ -1657,7 +1675,7 @@ fn insert_late_bound_lifetimes(map: &mut NamedRegionMap,
|
||||
}
|
||||
|
||||
struct AllCollector {
|
||||
regions: FxHashSet<ast::Name>,
|
||||
regions: FxHashSet<hir::LifetimeName>,
|
||||
impl_trait: bool
|
||||
}
|
||||
|
||||
|
@ -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));
|
||||
}
|
||||
|
||||
|
@ -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)) |
|
||||
|
@ -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,
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -876,7 +876,7 @@ impl Clean<Lifetime> for hir::Lifetime {
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
Lifetime(self.name.to_string())
|
||||
Lifetime(self.name.name().to_string())
|
||||
}
|
||||
}
|
||||
|
||||
@ -884,14 +884,14 @@ impl Clean<Lifetime> 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())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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 {
|
||||
|
20
src/test/compile-fail/E0637.rs
Normal file
20
src/test/compile-fail/E0637.rs
Normal file
@ -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 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, 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() {}
|
20
src/test/compile-fail/feature-gate-underscore-lifetimes.rs
Normal file
20
src/test/compile-fail/feature-gate-underscore-lifetimes.rs
Normal file
@ -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 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, 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);
|
||||
}
|
@ -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 `'_`
|
39
src/test/compile-fail/underscore-lifetime-binders.rs
Normal file
39
src/test/compile-fail/underscore-lifetime-binders.rs
Normal file
@ -0,0 +1,39 @@
|
||||
// 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 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, 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);
|
||||
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<'_>) {}
|
||||
|
||||
trait Meh<'a> {}
|
||||
impl<'a> Meh<'a> for u8 {}
|
||||
|
||||
fn meh() -> Box<for<'_> Meh<'_>> //~ ERROR invalid lifetime parameter name: `'_`
|
||||
//~^ ERROR missing lifetime specifier
|
||||
//~^^ ERROR missing lifetime specifier
|
||||
{
|
||||
Box::new(5u8)
|
||||
}
|
||||
|
||||
fn foo2(_: &'_ u8, y: &'_ u8) -> &'_ u8 { y } //~ ERROR missing lifetime specifier
|
||||
|
||||
fn main() {
|
||||
let x = 5;
|
||||
foo(Foo(&x));
|
||||
let _ = meh();
|
||||
}
|
15
src/test/compile-fail/underscore-lifetime-elison-mismatch.rs
Normal file
15
src/test/compile-fail/underscore-lifetime-elison-mismatch.rs
Normal file
@ -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 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, 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() {}
|
47
src/test/run-pass/underscore-lifetimes.rs
Normal file
47
src/test/run-pass/underscore-lifetimes.rs
Normal file
@ -0,0 +1,47 @@
|
||||
// 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 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, 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<'_>) {}
|
||||
|
||||
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,
|
||||
});
|
||||
}
|
Loading…
Reference in New Issue
Block a user