Skip to content

Commit e40cedb

Browse files
committed
Detect implicitly defined late bound lifetime parameters as well
1 parent 7ca378b commit e40cedb

File tree

5 files changed

+171
-34
lines changed

5 files changed

+171
-34
lines changed

src/librustc_typeck/collect.rs

+87-4
Original file line numberDiff line numberDiff line change
@@ -772,6 +772,92 @@ fn trait_def<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
772772
tcx.alloc_trait_def(def)
773773
}
774774

775+
fn has_late_bound_regions<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
776+
node: hir_map::Node<'tcx>)
777+
-> bool {
778+
struct LateBoundRegionsDetector<'a, 'tcx: 'a> {
779+
tcx: TyCtxt<'a, 'tcx, 'tcx>,
780+
binder_depth: usize,
781+
has_late_bound_regions: bool,
782+
}
783+
784+
impl<'a, 'tcx> Visitor<'tcx> for LateBoundRegionsDetector<'a, 'tcx> {
785+
fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'tcx> {
786+
NestedVisitorMap::None
787+
}
788+
789+
fn visit_ty(&mut self, ty: &'tcx hir::Ty) {
790+
if self.has_late_bound_regions { return }
791+
match ty.node {
792+
hir::TyBareFn(..) => {
793+
self.binder_depth += 1;
794+
intravisit::walk_ty(self, ty);
795+
self.binder_depth -= 1;
796+
}
797+
_ => intravisit::walk_ty(self, ty)
798+
}
799+
}
800+
801+
fn visit_poly_trait_ref(&mut self,
802+
tr: &'tcx hir::PolyTraitRef,
803+
m: hir::TraitBoundModifier) {
804+
if self.has_late_bound_regions { return }
805+
self.binder_depth += 1;
806+
intravisit::walk_poly_trait_ref(self, tr, m);
807+
self.binder_depth -= 1;
808+
}
809+
810+
fn visit_lifetime(&mut self, lt: &'tcx hir::Lifetime) {
811+
if self.has_late_bound_regions { return }
812+
813+
match self.tcx.named_region_map.defs.get(&lt.id).cloned() {
814+
Some(rl::Region::Static) | Some(rl::Region::EarlyBound(..)) => {}
815+
_ => self.has_late_bound_regions = true
816+
}
817+
}
818+
}
819+
820+
fn has_late_bound_regions<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
821+
generics: &'tcx hir::Generics,
822+
decl: &'tcx hir::FnDecl)
823+
-> bool {
824+
let mut visitor = LateBoundRegionsDetector {
825+
tcx, binder_depth: 0, has_late_bound_regions: false
826+
};
827+
for lifetime in &generics.lifetimes {
828+
if tcx.named_region_map.late_bound.contains(&lifetime.lifetime.id) {
829+
return true;
830+
}
831+
}
832+
visitor.visit_fn_decl(decl);
833+
visitor.has_late_bound_regions
834+
}
835+
836+
match node {
837+
hir_map::NodeTraitItem(item) => match item.node {
838+
hir::TraitItemKind::Method(ref sig, _) =>
839+
has_late_bound_regions(tcx, &sig.generics, &sig.decl),
840+
_ => false,
841+
},
842+
hir_map::NodeImplItem(item) => match item.node {
843+
hir::ImplItemKind::Method(ref sig, _) =>
844+
has_late_bound_regions(tcx, &sig.generics, &sig.decl),
845+
_ => false,
846+
},
847+
hir_map::NodeForeignItem(item) => match item.node {
848+
hir::ForeignItemFn(ref fn_decl, _, ref generics) =>
849+
has_late_bound_regions(tcx, generics, fn_decl),
850+
_ => false,
851+
},
852+
hir_map::NodeItem(item) => match item.node {
853+
hir::ItemFn(ref fn_decl, .., ref generics, _) =>
854+
has_late_bound_regions(tcx, generics, fn_decl),
855+
_ => false,
856+
},
857+
_ => false
858+
}
859+
}
860+
775861
fn generics_of<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
776862
def_id: DefId)
777863
-> &'tcx ty::Generics {
@@ -876,13 +962,11 @@ fn generics_of<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
876962

877963
let has_self = opt_self.is_some();
878964
let mut parent_has_self = false;
879-
let mut parent_has_late_bound_regions = false;
880965
let mut own_start = has_self as u32;
881966
let (parent_regions, parent_types) = parent_def_id.map_or((0, 0), |def_id| {
882967
let generics = tcx.generics_of(def_id);
883968
assert_eq!(has_self, false);
884969
parent_has_self = generics.has_self;
885-
parent_has_late_bound_regions = generics.has_late_bound_regions;
886970
own_start = generics.count() as u32;
887971
(generics.parent_regions + generics.regions.len() as u32,
888972
generics.parent_types + generics.types.len() as u32)
@@ -900,7 +984,6 @@ fn generics_of<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
900984
}
901985
}).collect::<Vec<_>>();
902986

903-
let has_late_bound_regions = regions.len() != ast_generics.lifetimes.len();
904987
let object_lifetime_defaults =
905988
tcx.named_region_map.object_lifetime_defaults.get(&node_id);
906989

@@ -963,7 +1046,7 @@ fn generics_of<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
9631046
types: types,
9641047
type_param_to_index: type_param_to_index,
9651048
has_self: has_self || parent_has_self,
966-
has_late_bound_regions: has_late_bound_regions || parent_has_late_bound_regions,
1049+
has_late_bound_regions: has_late_bound_regions(tcx, node),
9671050
})
9681051
}
9691052

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
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+
// All lifetime parameters in struct constructors are currently considered early bound,
12+
// i.e. `S::<ARGS>` is interpreted kinda like an associated item `S::<ARGS>::ctor`.
13+
// This behavior is a bit weird, because if equivalent constructor were written manually
14+
// it would get late bound lifetime parameters.
15+
// Variant constructors behave in the same way, lifetime parameters are considered
16+
// belonging to the enum and being early bound.
17+
// https://github.com/rust-lang/rust/issues/30904
18+
19+
struct S<'a, 'b>(&'a u8, &'b u8);
20+
enum E<'a, 'b> {
21+
V(&'a u8),
22+
U(&'b u8),
23+
}
24+
25+
fn main() {
26+
S(&0, &0); // OK
27+
S::<'static>(&0, &0);
28+
//~^ ERROR expected 2 lifetime parameters, found 1 lifetime parameter
29+
S::<'static, 'static, 'static>(&0, &0);
30+
//~^ ERROR expected at most 2 lifetime parameters, found 3 lifetime parameters
31+
E::V(&0); // OK
32+
E::V::<'static>(&0);
33+
//~^ ERROR expected 2 lifetime parameters, found 1 lifetime parameter
34+
E::V::<'static, 'static, 'static>(&0);
35+
//~^ ERROR expected at most 2 lifetime parameters, found 3 lifetime parameters
36+
}

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

+19-19
Original file line numberDiff line numberDiff line change
@@ -42,25 +42,25 @@ fn method_call() {
4242
//~| WARN this was previously accepted
4343

4444
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
45+
S.late_implicit::<'static>(&0, &0);
46+
//~^ ERROR cannot specify lifetime arguments explicitly
47+
//~| WARN this was previously accepted
48+
S.late_implicit::<'static, 'static>(&0, &0);
49+
//~^ ERROR cannot specify lifetime arguments explicitly
50+
//~| WARN this was previously accepted
51+
S.late_implicit::<'static, 'static, 'static>(&0, &0);
52+
//~^ ERROR cannot specify lifetime arguments explicitly
53+
//~| WARN this was previously accepted
5454
S.late_implicit_early(&0); // OK
5555
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
56+
//~^ ERROR cannot specify lifetime arguments explicitly
57+
//~| WARN this was previously accepted
58+
S.late_implicit_early::<'static, 'static>(&0);
59+
//~^ ERROR cannot specify lifetime arguments explicitly
60+
//~| WARN this was previously accepted
61+
S.late_implicit_early::<'static, 'static, 'static>(&0);
62+
//~^ ERROR cannot specify lifetime arguments explicitly
63+
//~| WARN this was previously accepted
6464
}
6565

6666
fn ufcs() {
@@ -69,8 +69,8 @@ fn ufcs() {
6969
//~| WARN this was previously accepted
7070

7171
S::late_implicit_early::<'static>(S, &0);
72-
//FIXME ERROR cannot specify lifetime arguments explicitly
73-
//FIXME WARN this was previously accepted
72+
//~^ ERROR cannot specify lifetime arguments explicitly
73+
//~| WARN this was previously accepted
7474
}
7575

7676
fn main() {}

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

+28-10
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,17 @@ impl S {
1616
fn early<'a, 'b>(self) -> (&'a u8, &'b u8) { loop {} }
1717
fn late_early<'a, 'b>(self, _: &'a u8) -> &'b u8 { loop {} }
1818
fn late_implicit_early<'b>(self, _: &u8) -> &'b u8 { loop {} }
19+
fn late_implicit_self_early<'b>(&self) -> &'b u8 { loop {} }
20+
fn late_unused_early<'a, 'b>(self) -> &'b u8 { loop {} }
1921
fn life_and_type<'a, T>(self) -> &'a T { loop {} }
22+
23+
// 'late lifetimes here belong to nested types not to the tested functions.
24+
fn early_tricky_explicit<'a>(_: for<'late> fn(&'late u8),
25+
_: Box<for<'late> Fn(&'late u8)>)
26+
-> &'a u8 { loop {} }
27+
fn early_tricky_implicit<'a>(_: fn(&u8),
28+
_: Box<Fn(&u8)>)
29+
-> &'a u8 { loop {} }
2030
}
2131

2232
fn method_call() {
@@ -46,21 +56,26 @@ fn ufcs() {
4656

4757
S::late_implicit(S, &0, &0); // OK
4858
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
59+
//~^ ERROR cannot specify lifetime arguments explicitly
5160
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
61+
//~^ ERROR cannot specify lifetime arguments explicitly
5462
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
63+
//~^ ERROR cannot specify lifetime arguments explicitly
5764
S::late_implicit_early(S, &0); // OK
5865
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
66+
//~^ ERROR cannot specify lifetime arguments explicitly
6167
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
68+
//~^ ERROR cannot specify lifetime arguments explicitly
69+
S::late_implicit_self_early(&S); // OK
70+
S::late_implicit_self_early::<'static, 'static>(&S);
71+
//~^ ERROR cannot specify lifetime arguments explicitly
72+
S::late_implicit_self_early::<'static, 'static, 'static>(&S);
73+
//~^ ERROR cannot specify lifetime arguments explicitly
74+
S::late_unused_early(S); // OK
75+
S::late_unused_early::<'static, 'static>(S);
76+
//~^ ERROR cannot specify lifetime arguments explicitly
77+
S::late_unused_early::<'static, 'static, 'static>(S);
78+
//~^ ERROR cannot specify lifetime arguments explicitly
6479

6580
S::early(S); // OK
6681
S::early::<'static>(S);
@@ -70,6 +85,9 @@ fn ufcs() {
7085
let _: &u8 = S::life_and_type::<'static>(S);
7186
S::life_and_type::<u8>(S);
7287
S::life_and_type::<'static, u8>(S);
88+
89+
S::early_tricky_explicit::<'static>(loop {}, loop {}); // OK
90+
S::early_tricky_implicit::<'static>(loop {}, loop {}); // OK
7391
}
7492

7593
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_dirty(cfg="cfail2")]
372+
#[rustc_metadata_clean(cfg="cfail2")]
373373
#[rustc_metadata_clean(cfg="cfail3")]
374374
pub fn add_lifetime_parameter_to_method<'a>(&self) { }
375375
}

0 commit comments

Comments
 (0)