about summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
authorPietro Albini <pietro@pietroalbini.org>2018-10-02 22:54:28 +0200
committerGitHub <noreply@github.com>2018-10-02 22:54:28 +0200
commitab338eadfacb7651540ef5f1babbc8d18f4ab451 (patch)
tree025718c911f79c541a9f6320b5faad0e8e6ba327 /src
parent49d4359f6df32663e220d1ba6a3ccfe345ba2979 (diff)
parent003c4ffa836acd6901fa0d4b00624fc012bd5bd3 (diff)
downloadrust-ab338eadfacb7651540ef5f1babbc8d18f4ab451.tar.gz
rust-ab338eadfacb7651540ef5f1babbc8d18f4ab451.zip
Rollup merge of #54458 - scottmcm:bug-54456, r=nikomatsakis
Allow both explicit and elided lifetimes in the same impl header

While still prohibiting explicit and in-band in the same header.

Fixes #54456

As usual, I don't know the broader context of the code I'm changing, so please let me know whatever I can do better.

Pre-existing test that mixing explicit and in-band remains an error: https://github.com/rust-lang/rust/blob/master/src/test/ui/in-band-lifetimes/E0688.rs
Diffstat (limited to 'src')
-rw-r--r--src/librustc/hir/lowering.rs36
-rw-r--r--src/librustc/hir/mod.rs21
-rw-r--r--src/librustc/ich/impls_hir.rs10
-rw-r--r--src/librustc/middle/resolve_lifetime.rs20
-rw-r--r--src/test/ui/impl-header-lifetime-elision/explicit-and-elided-same-header.rs25
5 files changed, 83 insertions, 29 deletions
diff --git a/src/librustc/hir/lowering.rs b/src/librustc/hir/lowering.rs
index 81d8a803c39..5be74368864 100644
--- a/src/librustc/hir/lowering.rs
+++ b/src/librustc/hir/lowering.rs
@@ -727,9 +727,15 @@ impl<'a> LoweringContext<'a> {
                 // Get the name we'll use to make the def-path. Note
                 // that collisions are ok here and this shouldn't
                 // really show up for end-user.
-                let str_name = match hir_name {
-                    ParamName::Plain(ident) => ident.as_interned_str(),
-                    ParamName::Fresh(_) => keywords::UnderscoreLifetime.name().as_interned_str(),
+                let (str_name, kind) = match hir_name {
+                    ParamName::Plain(ident) => (
+                        ident.as_interned_str(),
+                        hir::LifetimeParamKind::InBand,
+                    ),
+                    ParamName::Fresh(_) => (
+                        keywords::UnderscoreLifetime.name().as_interned_str(),
+                        hir::LifetimeParamKind::Elided,
+                    ),
                 };
 
                 // Add a definition for the in-band lifetime def
@@ -749,7 +755,7 @@ impl<'a> LoweringContext<'a> {
                     bounds: hir_vec![],
                     span,
                     pure_wrt_drop: false,
-                    kind: hir::GenericParamKind::Lifetime { in_band: true }
+                    kind: hir::GenericParamKind::Lifetime { kind }
                 }
             })
             .chain(in_band_ty_params.into_iter())
@@ -1509,11 +1515,15 @@ impl<'a> LoweringContext<'a> {
                         lifetime.span,
                     );
 
-                    let name = match name {
-                        hir::LifetimeName::Underscore => {
-                            hir::ParamName::Plain(keywords::UnderscoreLifetime.ident())
-                        }
-                        hir::LifetimeName::Param(param_name) => param_name,
+                    let (name, kind) = match name {
+                        hir::LifetimeName::Underscore => (
+                            hir::ParamName::Plain(keywords::UnderscoreLifetime.ident()),
+                            hir::LifetimeParamKind::Elided,
+                        ),
+                        hir::LifetimeName::Param(param_name) => (
+                            param_name,
+                            hir::LifetimeParamKind::Explicit,
+                        ),
                         _ => bug!("expected LifetimeName::Param or ParamName::Plain"),
                     };
 
@@ -1524,9 +1534,7 @@ impl<'a> LoweringContext<'a> {
                         pure_wrt_drop: false,
                         attrs: hir_vec![],
                         bounds: hir_vec![],
-                        kind: hir::GenericParamKind::Lifetime {
-                            in_band: false,
-                        }
+                        kind: hir::GenericParamKind::Lifetime { kind }
                     });
                 }
             }
@@ -2360,7 +2368,9 @@ impl<'a> LoweringContext<'a> {
                     pure_wrt_drop: attr::contains_name(&param.attrs, "may_dangle"),
                     attrs: self.lower_attrs(&param.attrs),
                     bounds,
-                    kind: hir::GenericParamKind::Lifetime { in_band: false }
+                    kind: hir::GenericParamKind::Lifetime {
+                        kind: hir::LifetimeParamKind::Explicit,
+                    }
                 };
 
                 self.is_collecting_in_band_lifetimes = was_collecting_in_band;
diff --git a/src/librustc/hir/mod.rs b/src/librustc/hir/mod.rs
index 088bee38116..a9ca5d9d30d 100644
--- a/src/librustc/hir/mod.rs
+++ b/src/librustc/hir/mod.rs
@@ -499,14 +499,27 @@ impl GenericBound {
 
 pub type GenericBounds = HirVec<GenericBound>;
 
+#[derive(Copy, Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Debug)]
+pub enum LifetimeParamKind {
+    // Indicates that the lifetime definition was explicitly declared, like:
+    // `fn foo<'a>(x: &'a u8) -> &'a u8 { x }`
+    Explicit,
+
+    // Indicates that the lifetime definition was synthetically added
+    // as a result of an in-band lifetime usage like:
+    // `fn foo(x: &'a u8) -> &'a u8 { x }`
+    InBand,
+
+    // Indication that the lifetime was elided like both cases here:
+    // `fn foo(x: &u8) -> &'_ u8 { x }`
+    Elided,
+}
+
 #[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
 pub enum GenericParamKind {
     /// A lifetime definition, eg `'a: 'b + 'c + 'd`.
     Lifetime {
-        // Indicates that the lifetime definition was synthetically added
-        // as a result of an in-band lifetime usage like:
-        // `fn foo(x: &'a u8) -> &'a u8 { x }`
-        in_band: bool,
+        kind: LifetimeParamKind,
     },
     Type {
         default: Option<P<Ty>>,
diff --git a/src/librustc/ich/impls_hir.rs b/src/librustc/ich/impls_hir.rs
index bc2eb5f442b..676c24a8d3d 100644
--- a/src/librustc/ich/impls_hir.rs
+++ b/src/librustc/ich/impls_hir.rs
@@ -207,14 +207,20 @@ impl_stable_hash_for!(struct hir::GenericParam {
     kind
 });
 
+impl_stable_hash_for!(enum hir::LifetimeParamKind {
+    Explicit,
+    InBand,
+    Elided
+});
+
 impl<'a> HashStable<StableHashingContext<'a>> for hir::GenericParamKind {
     fn hash_stable<W: StableHasherResult>(&self,
                                           hcx: &mut StableHashingContext<'a>,
                                           hasher: &mut StableHasher<W>) {
         mem::discriminant(self).hash_stable(hcx, hasher);
         match self {
-            hir::GenericParamKind::Lifetime { in_band } => {
-                in_band.hash_stable(hcx, hasher);
+            hir::GenericParamKind::Lifetime { kind } => {
+                kind.hash_stable(hcx, hasher);
             }
             hir::GenericParamKind::Type { ref default, synthetic } => {
                 default.hash_stable(hcx, hasher);
diff --git a/src/librustc/middle/resolve_lifetime.rs b/src/librustc/middle/resolve_lifetime.rs
index cda7d8d6b90..acdeeca1ce4 100644
--- a/src/librustc/middle/resolve_lifetime.rs
+++ b/src/librustc/middle/resolve_lifetime.rs
@@ -35,7 +35,7 @@ use syntax_pos::Span;
 use util::nodemap::{DefIdMap, FxHashMap, FxHashSet, NodeMap, NodeSet};
 
 use hir::intravisit::{self, NestedVisitorMap, Visitor};
-use hir::{self, GenericParamKind};
+use hir::{self, GenericParamKind, LifetimeParamKind};
 
 /// The origin of a named lifetime definition.
 ///
@@ -51,8 +51,8 @@ pub enum LifetimeDefOrigin {
 impl LifetimeDefOrigin {
     fn from_param(param: &GenericParam) -> Self {
         match param.kind {
-            GenericParamKind::Lifetime { in_band } => {
-                if in_band {
+            GenericParamKind::Lifetime { kind } => {
+                if kind == LifetimeParamKind::InBand {
                     LifetimeDefOrigin::InBand
                 } else {
                     LifetimeDefOrigin::Explicit
@@ -1087,15 +1087,15 @@ fn check_mixed_explicit_and_in_band_defs(
     tcx: TyCtxt<'_, '_, '_>,
     params: &P<[hir::GenericParam]>,
 ) {
-    let in_bands: Vec<_> = params.iter().filter_map(|param| match param.kind {
-        GenericParamKind::Lifetime { in_band, .. } => Some((in_band, param.span)),
+    let lifetime_params: Vec<_> = params.iter().filter_map(|param| match param.kind {
+        GenericParamKind::Lifetime { kind, .. } => Some((kind, param.span)),
         _ => None,
     }).collect();
-    let out_of_band = in_bands.iter().find(|(in_band, _)| !in_band);
-    let in_band = in_bands.iter().find(|(in_band, _)| *in_band);
+    let explicit = lifetime_params.iter().find(|(kind, _)| *kind == LifetimeParamKind::Explicit);
+    let in_band = lifetime_params.iter().find(|(kind, _)| *kind == LifetimeParamKind::InBand);
 
-    if let (Some((_, out_of_band_span)), Some((_, in_band_span)))
-        = (out_of_band, in_band) {
+    if let (Some((_, explicit_span)), Some((_, in_band_span)))
+        = (explicit, in_band) {
         struct_span_err!(
             tcx.sess,
             *in_band_span,
@@ -1104,7 +1104,7 @@ fn check_mixed_explicit_and_in_band_defs(
         ).span_label(
             *in_band_span,
             "in-band lifetime definition here",
-        ).span_label(*out_of_band_span, "explicit lifetime definition here")
+        ).span_label(*explicit_span, "explicit lifetime definition here")
         .emit();
     }
 }
diff --git a/src/test/ui/impl-header-lifetime-elision/explicit-and-elided-same-header.rs b/src/test/ui/impl-header-lifetime-elision/explicit-and-elided-same-header.rs
new file mode 100644
index 00000000000..56dd6691abb
--- /dev/null
+++ b/src/test/ui/impl-header-lifetime-elision/explicit-and-elided-same-header.rs
@@ -0,0 +1,25 @@
+// Copyright 2018 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.
+
+// run-pass
+
+#![allow(warnings)]
+
+#![feature(impl_header_lifetime_elision)]
+
+// This works for functions...
+fn foo<'a>(x: &str, y: &'a str) {}
+
+// ...so this should work for impls
+impl<'a> Foo<&str> for &'a str {}
+trait Foo<T> {}
+
+fn main() {
+}