Skip to content

Commit 7ca378b

Browse files
committed
Prohibit lifetime arguments in path segments with late bound lifetime parameters
1 parent 9967e9e commit 7ca378b

File tree

12 files changed

+202
-50
lines changed

12 files changed

+202
-50
lines changed

src/librustc/ich/impls_ty.rs

+2
Original file line numberDiff line numberDiff line change
@@ -346,6 +346,7 @@ impl<'a, 'gcx, 'tcx> HashStable<StableHashingContext<'a, 'gcx, 'tcx>> for ty::Ge
346346
// `def_id.index` (`def_id.krate` is the same as the item's).
347347
type_param_to_index: _, // Don't hash this
348348
has_self,
349+
has_late_bound_regions,
349350
} = *self;
350351

351352
parent.hash_stable(hcx, hasher);
@@ -354,6 +355,7 @@ impl<'a, 'gcx, 'tcx> HashStable<StableHashingContext<'a, 'gcx, 'tcx>> for ty::Ge
354355
regions.hash_stable(hcx, hasher);
355356
types.hash_stable(hcx, hasher);
356357
has_self.hash_stable(hcx, hasher);
358+
has_late_bound_regions.hash_stable(hcx, hasher);
357359
}
358360
}
359361

src/librustc/lint/builtin.rs

+7
Original file line numberDiff line numberDiff line change
@@ -204,6 +204,12 @@ declare_lint! {
204204
"detects parenthesized generic parameters in type and module names"
205205
}
206206

207+
declare_lint! {
208+
pub LATE_BOUND_LIFETIME_ARGUMENTS,
209+
Deny,
210+
"detects generic lifetime arguments in path segments with late bound lifetime parameters"
211+
}
212+
207213
declare_lint! {
208214
pub DEPRECATED,
209215
Warn,
@@ -249,6 +255,7 @@ impl LintPass for HardwiredLints {
249255
LEGACY_CONSTRUCTOR_VISIBILITY,
250256
MISSING_FRAGMENT_SPECIFIER,
251257
PARENTHESIZED_PARAMS_IN_TYPES_AND_MODULES,
258+
LATE_BOUND_LIFETIME_ARGUMENTS,
252259
DEPRECATED
253260
)
254261
}

src/librustc/ty/mod.rs

+1
Original file line numberDiff line numberDiff line change
@@ -719,6 +719,7 @@ pub struct Generics {
719719
pub type_param_to_index: BTreeMap<DefIndex, u32>,
720720

721721
pub has_self: bool,
722+
pub has_late_bound_regions: bool,
722723
}
723724

724725
impl Generics {

src/librustc_lint/lib.rs

+5-1
Original file line numberDiff line numberDiff line change
@@ -235,7 +235,11 @@ pub fn register_builtins(store: &mut lint::LintStore, sess: Option<&Session>) {
235235
FutureIncompatibleInfo {
236236
id: LintId::of(PARENTHESIZED_PARAMS_IN_TYPES_AND_MODULES),
237237
reference: "issue #42238 <https://github.com/rust-lang/rust/issues/42238>",
238-
}
238+
},
239+
FutureIncompatibleInfo {
240+
id: LintId::of(LATE_BOUND_LIFETIME_ARGUMENTS),
241+
reference: "issue #42868 <https://github.com/rust-lang/rust/issues/42868>",
242+
},
239243
]);
240244

241245
// Register renamed and removed lints

src/librustc_typeck/check/method/confirm.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -288,7 +288,7 @@ impl<'a, 'gcx, 'tcx> ConfirmContext<'a, 'gcx, 'tcx> {
288288
// variables.
289289
let method_generics = self.tcx.generics_of(pick.item.def_id);
290290
let mut fn_segment = Some((segment, method_generics));
291-
self.fcx.check_path_parameter_count(self.span, &mut fn_segment);
291+
self.fcx.check_path_parameter_count(self.span, &mut fn_segment, true);
292292

293293
// Create subst for early-bound lifetime parameters, combining
294294
// parameters from the type and those from the method.

src/librustc_typeck/check/mod.rs

+51-30
Original file line numberDiff line numberDiff line change
@@ -4491,8 +4491,8 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
44914491
// variables. If the user provided some types, we may still need
44924492
// to add defaults. If the user provided *too many* types, that's
44934493
// a problem.
4494-
self.check_path_parameter_count(span, &mut type_segment);
4495-
self.check_path_parameter_count(span, &mut fn_segment);
4494+
self.check_path_parameter_count(span, &mut type_segment, false);
4495+
self.check_path_parameter_count(span, &mut fn_segment, false);
44964496

44974497
let (fn_start, has_self) = match (type_segment, fn_segment) {
44984498
(_, Some((_, generics))) => {
@@ -4618,7 +4618,8 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
46184618
/// Report errors if the provided parameters are too few or too many.
46194619
fn check_path_parameter_count(&self,
46204620
span: Span,
4621-
segment: &mut Option<(&hir::PathSegment, &ty::Generics)>) {
4621+
segment: &mut Option<(&hir::PathSegment, &ty::Generics)>,
4622+
is_method_call: bool) {
46224623
let (lifetimes, types, infer_types, bindings) = {
46234624
match segment.map(|(s, _)| &s.parameters) {
46244625
Some(&hir::AngleBracketedParameters(ref data)) => {
@@ -4632,6 +4633,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
46324633
None => (&[][..], &[][..], true, &[][..])
46334634
}
46344635
};
4636+
let infer_lifetimes = lifetimes.len() == 0;
46354637

46364638
let count_lifetime_params = |n| {
46374639
format!("{} lifetime parameter{}", n, if n == 1 { "" } else { "s" })
@@ -4640,32 +4642,6 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
46404642
format!("{} type parameter{}", n, if n == 1 { "" } else { "s" })
46414643
};
46424644

4643-
// Check provided lifetime parameters.
4644-
let lifetime_defs = segment.map_or(&[][..], |(_, generics)| &generics.regions);
4645-
if lifetimes.len() > lifetime_defs.len() {
4646-
let expected_text = count_lifetime_params(lifetime_defs.len());
4647-
let actual_text = count_lifetime_params(lifetimes.len());
4648-
struct_span_err!(self.tcx.sess, span, E0088,
4649-
"too many lifetime parameters provided: \
4650-
expected at most {}, found {}",
4651-
expected_text, actual_text)
4652-
.span_label(span, format!("expected {}", expected_text))
4653-
.emit();
4654-
} else if lifetimes.len() > 0 && lifetimes.len() < lifetime_defs.len() {
4655-
let expected_text = count_lifetime_params(lifetime_defs.len());
4656-
let actual_text = count_lifetime_params(lifetimes.len());
4657-
struct_span_err!(self.tcx.sess, span, E0090,
4658-
"too few lifetime parameters provided: \
4659-
expected {}, found {}",
4660-
expected_text, actual_text)
4661-
.span_label(span, format!("expected {}", expected_text))
4662-
.emit();
4663-
}
4664-
4665-
// The case where there is not enough lifetime parameters is not checked,
4666-
// because this is not possible - a function never takes lifetime parameters.
4667-
// See discussion for Pull Request 36208.
4668-
46694645
// Check provided type parameters.
46704646
let type_defs = segment.map_or(&[][..], |(_, generics)| {
46714647
if generics.parent.is_none() {
@@ -4690,7 +4666,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
46904666
// type parameters, we force instantiate_value_path to
46914667
// use inference variables instead of the provided types.
46924668
*segment = None;
4693-
} else if !infer_types && types.len() < required_len {
4669+
} else if types.len() < required_len && !infer_types {
46944670
let expected_text = count_type_params(required_len);
46954671
let actual_text = count_type_params(types.len());
46964672
struct_span_err!(self.tcx.sess, span, E0089,
@@ -4706,6 +4682,51 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
47064682
"unexpected binding of associated item in expression path \
47074683
(only allowed in type paths)");
47084684
}
4685+
4686+
// Check provided lifetime parameters.
4687+
let lifetime_defs = segment.map_or(&[][..], |(_, generics)| &generics.regions);
4688+
let required_len = lifetime_defs.len();
4689+
4690+
// Prohibit explicit lifetime arguments if late bound lifetime parameters are present.
4691+
let has_late_bound_lifetime_defs =
4692+
segment.map_or(false, |(_, generics)| generics.has_late_bound_regions);
4693+
if has_late_bound_lifetime_defs && !lifetimes.is_empty() {
4694+
// Report this as a lint only if no error was reported previously.
4695+
if !is_method_call && (lifetimes.len() > lifetime_defs.len() ||
4696+
lifetimes.len() < required_len && !infer_lifetimes) {
4697+
self.tcx.sess.span_err(lifetimes[0].span,
4698+
"cannot specify lifetime arguments explicitly \
4699+
if late bound lifetime parameters are present");
4700+
} else {
4701+
self.tcx.sess.add_lint(lint::builtin::LATE_BOUND_LIFETIME_ARGUMENTS,
4702+
lifetimes[0].id, lifetimes[0].span,
4703+
format!("cannot specify lifetime arguments explicitly \
4704+
if late bound lifetime parameters are present"));
4705+
}
4706+
*segment = None;
4707+
return;
4708+
}
4709+
4710+
if lifetimes.len() > lifetime_defs.len() {
4711+
let span = lifetimes[lifetime_defs.len()].span;
4712+
let expected_text = count_lifetime_params(lifetime_defs.len());
4713+
let actual_text = count_lifetime_params(lifetimes.len());
4714+
struct_span_err!(self.tcx.sess, span, E0088,
4715+
"too many lifetime parameters provided: \
4716+
expected at most {}, found {}",
4717+
expected_text, actual_text)
4718+
.span_label(span, format!("expected {}", expected_text))
4719+
.emit();
4720+
} else if lifetimes.len() < required_len && !infer_lifetimes {
4721+
let expected_text = count_lifetime_params(lifetime_defs.len());
4722+
let actual_text = count_lifetime_params(lifetimes.len());
4723+
struct_span_err!(self.tcx.sess, span, E0090,
4724+
"too few lifetime parameters provided: \
4725+
expected {}, found {}",
4726+
expected_text, actual_text)
4727+
.span_label(span, format!("expected {}", expected_text))
4728+
.emit();
4729+
}
47094730
}
47104731

47114732
fn structurally_resolve_type_or_else<F>(&self, sp: Span, ty: Ty<'tcx>, f: F)

src/librustc_typeck/collect.rs

+5-1
Original file line numberDiff line numberDiff line change
@@ -876,11 +876,13 @@ fn generics_of<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
876876

877877
let has_self = opt_self.is_some();
878878
let mut parent_has_self = false;
879+
let mut parent_has_late_bound_regions = false;
879880
let mut own_start = has_self as u32;
880881
let (parent_regions, parent_types) = parent_def_id.map_or((0, 0), |def_id| {
881882
let generics = tcx.generics_of(def_id);
882883
assert_eq!(has_self, false);
883884
parent_has_self = generics.has_self;
885+
parent_has_late_bound_regions = generics.has_late_bound_regions;
884886
own_start = generics.count() as u32;
885887
(generics.parent_regions + generics.regions.len() as u32,
886888
generics.parent_types + generics.types.len() as u32)
@@ -898,6 +900,7 @@ fn generics_of<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
898900
}
899901
}).collect::<Vec<_>>();
900902

903+
let has_late_bound_regions = regions.len() != ast_generics.lifetimes.len();
901904
let object_lifetime_defaults =
902905
tcx.named_region_map.object_lifetime_defaults.get(&node_id);
903906

@@ -959,7 +962,8 @@ fn generics_of<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
959962
regions: regions,
960963
types: types,
961964
type_param_to_index: type_param_to_index,
962-
has_self: has_self || parent_has_self
965+
has_self: has_self || parent_has_self,
966+
has_late_bound_regions: has_late_bound_regions || parent_has_late_bound_regions,
963967
})
964968
}
965969

src/test/compile-fail/E0088.rs

+3-8
Original file line numberDiff line numberDiff line change
@@ -9,14 +9,9 @@
99
// except according to those terms.
1010

1111
fn f() {}
12-
fn g<'a>() {}
12+
fn g<'a>() -> &'a u8 { loop {} }
1313

1414
fn main() {
15-
f::<'static>();
16-
//~^ ERROR expected at most 0 lifetime parameters, found 1 lifetime parameter [E0088]
17-
//~| NOTE expected 0 lifetime parameters
18-
19-
g::<'static, 'static>();
20-
//~^ ERROR expected at most 0 lifetime parameters, found 2 lifetime parameters [E0088]
21-
//~| NOTE expected 0 lifetime parameters
15+
f::<'static>(); //~ ERROR E0088
16+
g::<'static, 'static>(); //~ ERROR E0088
2217
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
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+
#![allow(unused)]
12+
13+
struct S;
14+
15+
impl S {
16+
fn late<'a, 'b>(self, _: &'a u8, _: &'b u8) {}
17+
fn late_implicit(self, _: &u8, _: &u8) {}
18+
fn late_early<'a, 'b>(self, _: &'a u8) -> &'b u8 { loop {} }
19+
fn late_implicit_early<'b>(self, _: &u8) -> &'b u8 { loop {} }
20+
}
21+
22+
fn method_call() {
23+
S.late(&0, &0); // OK
24+
S.late::<'static>(&0, &0);
25+
//~^ ERROR cannot specify lifetime arguments explicitly
26+
//~| WARN this was previously accepted
27+
S.late::<'static, 'static>(&0, &0);
28+
//~^ ERROR cannot specify lifetime arguments explicitly
29+
//~| WARN this was previously accepted
30+
S.late::<'static, 'static, 'static>(&0, &0);
31+
//~^ ERROR cannot specify lifetime arguments explicitly
32+
//~| WARN this was previously accepted
33+
S.late_early(&0); // OK
34+
S.late_early::<'static>(&0);
35+
//~^ ERROR cannot specify lifetime arguments explicitly
36+
//~| WARN this was previously accepted
37+
S.late_early::<'static, 'static>(&0);
38+
//~^ ERROR cannot specify lifetime arguments explicitly
39+
//~| WARN this was previously accepted
40+
S.late_early::<'static, 'static, 'static>(&0);
41+
//~^ ERROR cannot specify lifetime arguments explicitly
42+
//~| WARN this was previously accepted
43+
44+
S.late_implicit(&0, &0); // OK
45+
// S.late_implicit::<'static>(&0, &0);
46+
//FIXME ERROR cannot specify lifetime arguments explicitly
47+
//FIXME WARN this was previously accepted
48+
// S.late_implicit::<'static, 'static>(&0, &0);
49+
//FIXME ERROR cannot specify lifetime arguments explicitly
50+
//FIXME WARN this was previously accepted
51+
// S.late_implicit::<'static, 'static, 'static>(&0, &0);
52+
//FIXME ERROR cannot specify lifetime arguments explicitly
53+
//FIXME WARN this was previously accepted
54+
S.late_implicit_early(&0); // OK
55+
S.late_implicit_early::<'static>(&0);
56+
//FIXME ERROR cannot specify lifetime arguments explicitly
57+
//FIXME WARN this was previously accepted
58+
// S.late_implicit_early::<'static, 'static>(&0);
59+
//FIXME ERROR cannot specify lifetime arguments explicitly
60+
//FIXME WARN this was previously accepted
61+
// S.late_implicit_early::<'static, 'static, 'static>(&0);
62+
//FIXME ERROR cannot specify lifetime arguments explicitly
63+
//FIXME WARN this was previously accepted
64+
}
65+
66+
fn ufcs() {
67+
S::late_early::<'static>(S, &0);
68+
//~^ ERROR cannot specify lifetime arguments explicitly
69+
//~| WARN this was previously accepted
70+
71+
S::late_implicit_early::<'static>(S, &0);
72+
//FIXME ERROR cannot specify lifetime arguments explicitly
73+
//FIXME WARN this was previously accepted
74+
}
75+
76+
fn main() {}

src/test/compile-fail/method-call-lifetime-args.rs

+49-7
Original file line numberDiff line numberDiff line change
@@ -12,16 +12,14 @@ struct S;
1212

1313
impl S {
1414
fn late<'a, 'b>(self, _: &'a u8, _: &'b u8) {}
15+
fn late_implicit(self, _: &u8, _: &u8) {}
1516
fn early<'a, 'b>(self) -> (&'a u8, &'b u8) { loop {} }
16-
fn life_and_type<'a, T>(&self) -> &'a T { loop {} }
17+
fn late_early<'a, 'b>(self, _: &'a u8) -> &'b u8 { loop {} }
18+
fn late_implicit_early<'b>(self, _: &u8) -> &'b u8 { loop {} }
19+
fn life_and_type<'a, T>(self) -> &'a T { loop {} }
1720
}
1821

19-
fn main() {
20-
S.late(&0, &0); // OK
21-
S.late::<'static>(&0, &0);
22-
//~^ ERROR expected at most 0 lifetime parameters, found 1 lifetime parameter
23-
S.late::<'static, 'static, 'static>(&0, &0);
24-
//~^ ERROR expected at most 0 lifetime parameters, found 3 lifetime parameter
22+
fn method_call() {
2523
S.early(); // OK
2624
S.early::<'static>();
2725
//~^ ERROR expected 2 lifetime parameters, found 1 lifetime parameter
@@ -31,3 +29,47 @@ fn main() {
3129
S.life_and_type::<u8>();
3230
S.life_and_type::<'static, u8>();
3331
}
32+
33+
fn ufcs() {
34+
S::late(S, &0, &0); // OK
35+
S::late::<'static>(S, &0, &0);
36+
//~^ ERROR cannot specify lifetime arguments explicitly
37+
S::late::<'static, 'static>(S, &0, &0);
38+
//~^ ERROR cannot specify lifetime arguments explicitly
39+
S::late::<'static, 'static, 'static>(S, &0, &0);
40+
//~^ ERROR cannot specify lifetime arguments explicitly
41+
S::late_early(S, &0); // OK
42+
S::late_early::<'static, 'static>(S, &0);
43+
//~^ ERROR cannot specify lifetime arguments explicitly
44+
S::late_early::<'static, 'static, 'static>(S, &0);
45+
//~^ ERROR cannot specify lifetime arguments explicitly
46+
47+
S::late_implicit(S, &0, &0); // OK
48+
S::late_implicit::<'static>(S, &0, &0);
49+
//~^ ERROR expected at most 0 lifetime parameters, found 1 lifetime parameter
50+
//FIXME ERROR cannot specify lifetime arguments explicitly
51+
S::late_implicit::<'static, 'static>(S, &0, &0);
52+
//~^ ERROR expected at most 0 lifetime parameters, found 2 lifetime parameters
53+
//FIXME ERROR cannot specify lifetime arguments explicitly
54+
S::late_implicit::<'static, 'static, 'static>(S, &0, &0);
55+
//~^ ERROR expected at most 0 lifetime parameters, found 3 lifetime parameters
56+
//FIXME ERROR cannot specify lifetime arguments explicitly
57+
S::late_implicit_early(S, &0); // OK
58+
S::late_implicit_early::<'static, 'static>(S, &0);
59+
//~^ ERROR expected at most 1 lifetime parameter, found 2 lifetime parameters
60+
//FIXME ERROR cannot specify lifetime arguments explicitly
61+
S::late_implicit_early::<'static, 'static, 'static>(S, &0);
62+
//~^ ERROR expected at most 1 lifetime parameter, found 3 lifetime parameters
63+
//FIXME ERROR cannot specify lifetime arguments explicitly
64+
65+
S::early(S); // OK
66+
S::early::<'static>(S);
67+
//~^ ERROR expected 2 lifetime parameters, found 1 lifetime parameter
68+
S::early::<'static, 'static, 'static>(S);
69+
//~^ ERROR expected at most 2 lifetime parameters, found 3 lifetime parameters
70+
let _: &u8 = S::life_and_type::<'static>(S);
71+
S::life_and_type::<u8>(S);
72+
S::life_and_type::<'static, u8>(S);
73+
}
74+
75+
fn main() {}

src/test/incremental/hashes/inherent_impls.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -369,7 +369,7 @@ impl Foo {
369369
impl Foo {
370370
#[rustc_dirty(label="Hir", cfg="cfail2")]
371371
#[rustc_clean(label="Hir", cfg="cfail3")]
372-
#[rustc_metadata_clean(cfg="cfail2")] // Apparently unused lifetimes don't show up in the type.
372+
#[rustc_metadata_dirty(cfg="cfail2")]
373373
#[rustc_metadata_clean(cfg="cfail3")]
374374
pub fn add_lifetime_parameter_to_method<'a>(&self) { }
375375
}

0 commit comments

Comments
 (0)