Skip to content

Commit ab338ea

Browse files
authored
Rollup merge of rust-lang#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 rust-lang#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
2 parents 49d4359 + 003c4ff commit ab338ea

File tree

5 files changed

+83
-29
lines changed

5 files changed

+83
-29
lines changed

src/librustc/hir/lowering.rs

+23-13
Original file line numberDiff line numberDiff line change
@@ -727,9 +727,15 @@ impl<'a> LoweringContext<'a> {
727727
// Get the name we'll use to make the def-path. Note
728728
// that collisions are ok here and this shouldn't
729729
// really show up for end-user.
730-
let str_name = match hir_name {
731-
ParamName::Plain(ident) => ident.as_interned_str(),
732-
ParamName::Fresh(_) => keywords::UnderscoreLifetime.name().as_interned_str(),
730+
let (str_name, kind) = match hir_name {
731+
ParamName::Plain(ident) => (
732+
ident.as_interned_str(),
733+
hir::LifetimeParamKind::InBand,
734+
),
735+
ParamName::Fresh(_) => (
736+
keywords::UnderscoreLifetime.name().as_interned_str(),
737+
hir::LifetimeParamKind::Elided,
738+
),
733739
};
734740

735741
// Add a definition for the in-band lifetime def
@@ -749,7 +755,7 @@ impl<'a> LoweringContext<'a> {
749755
bounds: hir_vec![],
750756
span,
751757
pure_wrt_drop: false,
752-
kind: hir::GenericParamKind::Lifetime { in_band: true }
758+
kind: hir::GenericParamKind::Lifetime { kind }
753759
}
754760
})
755761
.chain(in_band_ty_params.into_iter())
@@ -1509,11 +1515,15 @@ impl<'a> LoweringContext<'a> {
15091515
lifetime.span,
15101516
);
15111517

1512-
let name = match name {
1513-
hir::LifetimeName::Underscore => {
1514-
hir::ParamName::Plain(keywords::UnderscoreLifetime.ident())
1515-
}
1516-
hir::LifetimeName::Param(param_name) => param_name,
1518+
let (name, kind) = match name {
1519+
hir::LifetimeName::Underscore => (
1520+
hir::ParamName::Plain(keywords::UnderscoreLifetime.ident()),
1521+
hir::LifetimeParamKind::Elided,
1522+
),
1523+
hir::LifetimeName::Param(param_name) => (
1524+
param_name,
1525+
hir::LifetimeParamKind::Explicit,
1526+
),
15171527
_ => bug!("expected LifetimeName::Param or ParamName::Plain"),
15181528
};
15191529

@@ -1524,9 +1534,7 @@ impl<'a> LoweringContext<'a> {
15241534
pure_wrt_drop: false,
15251535
attrs: hir_vec![],
15261536
bounds: hir_vec![],
1527-
kind: hir::GenericParamKind::Lifetime {
1528-
in_band: false,
1529-
}
1537+
kind: hir::GenericParamKind::Lifetime { kind }
15301538
});
15311539
}
15321540
}
@@ -2360,7 +2368,9 @@ impl<'a> LoweringContext<'a> {
23602368
pure_wrt_drop: attr::contains_name(&param.attrs, "may_dangle"),
23612369
attrs: self.lower_attrs(&param.attrs),
23622370
bounds,
2363-
kind: hir::GenericParamKind::Lifetime { in_band: false }
2371+
kind: hir::GenericParamKind::Lifetime {
2372+
kind: hir::LifetimeParamKind::Explicit,
2373+
}
23642374
};
23652375

23662376
self.is_collecting_in_band_lifetimes = was_collecting_in_band;

src/librustc/hir/mod.rs

+17-4
Original file line numberDiff line numberDiff line change
@@ -499,14 +499,27 @@ impl GenericBound {
499499

500500
pub type GenericBounds = HirVec<GenericBound>;
501501

502+
#[derive(Copy, Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Debug)]
503+
pub enum LifetimeParamKind {
504+
// Indicates that the lifetime definition was explicitly declared, like:
505+
// `fn foo<'a>(x: &'a u8) -> &'a u8 { x }`
506+
Explicit,
507+
508+
// Indicates that the lifetime definition was synthetically added
509+
// as a result of an in-band lifetime usage like:
510+
// `fn foo(x: &'a u8) -> &'a u8 { x }`
511+
InBand,
512+
513+
// Indication that the lifetime was elided like both cases here:
514+
// `fn foo(x: &u8) -> &'_ u8 { x }`
515+
Elided,
516+
}
517+
502518
#[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
503519
pub enum GenericParamKind {
504520
/// A lifetime definition, eg `'a: 'b + 'c + 'd`.
505521
Lifetime {
506-
// Indicates that the lifetime definition was synthetically added
507-
// as a result of an in-band lifetime usage like:
508-
// `fn foo(x: &'a u8) -> &'a u8 { x }`
509-
in_band: bool,
522+
kind: LifetimeParamKind,
510523
},
511524
Type {
512525
default: Option<P<Ty>>,

src/librustc/ich/impls_hir.rs

+8-2
Original file line numberDiff line numberDiff line change
@@ -207,14 +207,20 @@ impl_stable_hash_for!(struct hir::GenericParam {
207207
kind
208208
});
209209

210+
impl_stable_hash_for!(enum hir::LifetimeParamKind {
211+
Explicit,
212+
InBand,
213+
Elided
214+
});
215+
210216
impl<'a> HashStable<StableHashingContext<'a>> for hir::GenericParamKind {
211217
fn hash_stable<W: StableHasherResult>(&self,
212218
hcx: &mut StableHashingContext<'a>,
213219
hasher: &mut StableHasher<W>) {
214220
mem::discriminant(self).hash_stable(hcx, hasher);
215221
match self {
216-
hir::GenericParamKind::Lifetime { in_band } => {
217-
in_band.hash_stable(hcx, hasher);
222+
hir::GenericParamKind::Lifetime { kind } => {
223+
kind.hash_stable(hcx, hasher);
218224
}
219225
hir::GenericParamKind::Type { ref default, synthetic } => {
220226
default.hash_stable(hcx, hasher);

src/librustc/middle/resolve_lifetime.rs

+10-10
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ use syntax_pos::Span;
3535
use util::nodemap::{DefIdMap, FxHashMap, FxHashSet, NodeMap, NodeSet};
3636

3737
use hir::intravisit::{self, NestedVisitorMap, Visitor};
38-
use hir::{self, GenericParamKind};
38+
use hir::{self, GenericParamKind, LifetimeParamKind};
3939

4040
/// The origin of a named lifetime definition.
4141
///
@@ -51,8 +51,8 @@ pub enum LifetimeDefOrigin {
5151
impl LifetimeDefOrigin {
5252
fn from_param(param: &GenericParam) -> Self {
5353
match param.kind {
54-
GenericParamKind::Lifetime { in_band } => {
55-
if in_band {
54+
GenericParamKind::Lifetime { kind } => {
55+
if kind == LifetimeParamKind::InBand {
5656
LifetimeDefOrigin::InBand
5757
} else {
5858
LifetimeDefOrigin::Explicit
@@ -1087,15 +1087,15 @@ fn check_mixed_explicit_and_in_band_defs(
10871087
tcx: TyCtxt<'_, '_, '_>,
10881088
params: &P<[hir::GenericParam]>,
10891089
) {
1090-
let in_bands: Vec<_> = params.iter().filter_map(|param| match param.kind {
1091-
GenericParamKind::Lifetime { in_band, .. } => Some((in_band, param.span)),
1090+
let lifetime_params: Vec<_> = params.iter().filter_map(|param| match param.kind {
1091+
GenericParamKind::Lifetime { kind, .. } => Some((kind, param.span)),
10921092
_ => None,
10931093
}).collect();
1094-
let out_of_band = in_bands.iter().find(|(in_band, _)| !in_band);
1095-
let in_band = in_bands.iter().find(|(in_band, _)| *in_band);
1094+
let explicit = lifetime_params.iter().find(|(kind, _)| *kind == LifetimeParamKind::Explicit);
1095+
let in_band = lifetime_params.iter().find(|(kind, _)| *kind == LifetimeParamKind::InBand);
10961096

1097-
if let (Some((_, out_of_band_span)), Some((_, in_band_span)))
1098-
= (out_of_band, in_band) {
1097+
if let (Some((_, explicit_span)), Some((_, in_band_span)))
1098+
= (explicit, in_band) {
10991099
struct_span_err!(
11001100
tcx.sess,
11011101
*in_band_span,
@@ -1104,7 +1104,7 @@ fn check_mixed_explicit_and_in_band_defs(
11041104
).span_label(
11051105
*in_band_span,
11061106
"in-band lifetime definition here",
1107-
).span_label(*out_of_band_span, "explicit lifetime definition here")
1107+
).span_label(*explicit_span, "explicit lifetime definition here")
11081108
.emit();
11091109
}
11101110
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
// Copyright 2018 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+
// run-pass
12+
13+
#![allow(warnings)]
14+
15+
#![feature(impl_header_lifetime_elision)]
16+
17+
// This works for functions...
18+
fn foo<'a>(x: &str, y: &'a str) {}
19+
20+
// ...so this should work for impls
21+
impl<'a> Foo<&str> for &'a str {}
22+
trait Foo<T> {}
23+
24+
fn main() {
25+
}

0 commit comments

Comments
 (0)