mirror of
https://github.com/rust-lang/rust.git
synced 2025-02-16 00:43:50 +00:00
Detect implicitly defined late bound lifetime parameters as well
This commit is contained in:
parent
7ca378b251
commit
e40cedb393
@ -772,6 +772,92 @@ fn trait_def<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
||||
tcx.alloc_trait_def(def)
|
||||
}
|
||||
|
||||
fn has_late_bound_regions<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
||||
node: hir_map::Node<'tcx>)
|
||||
-> bool {
|
||||
struct LateBoundRegionsDetector<'a, 'tcx: 'a> {
|
||||
tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
||||
binder_depth: usize,
|
||||
has_late_bound_regions: bool,
|
||||
}
|
||||
|
||||
impl<'a, 'tcx> Visitor<'tcx> for LateBoundRegionsDetector<'a, 'tcx> {
|
||||
fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'tcx> {
|
||||
NestedVisitorMap::None
|
||||
}
|
||||
|
||||
fn visit_ty(&mut self, ty: &'tcx hir::Ty) {
|
||||
if self.has_late_bound_regions { return }
|
||||
match ty.node {
|
||||
hir::TyBareFn(..) => {
|
||||
self.binder_depth += 1;
|
||||
intravisit::walk_ty(self, ty);
|
||||
self.binder_depth -= 1;
|
||||
}
|
||||
_ => intravisit::walk_ty(self, ty)
|
||||
}
|
||||
}
|
||||
|
||||
fn visit_poly_trait_ref(&mut self,
|
||||
tr: &'tcx hir::PolyTraitRef,
|
||||
m: hir::TraitBoundModifier) {
|
||||
if self.has_late_bound_regions { return }
|
||||
self.binder_depth += 1;
|
||||
intravisit::walk_poly_trait_ref(self, tr, m);
|
||||
self.binder_depth -= 1;
|
||||
}
|
||||
|
||||
fn visit_lifetime(&mut self, lt: &'tcx hir::Lifetime) {
|
||||
if self.has_late_bound_regions { return }
|
||||
|
||||
match self.tcx.named_region_map.defs.get(<.id).cloned() {
|
||||
Some(rl::Region::Static) | Some(rl::Region::EarlyBound(..)) => {}
|
||||
_ => self.has_late_bound_regions = true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn has_late_bound_regions<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
||||
generics: &'tcx hir::Generics,
|
||||
decl: &'tcx hir::FnDecl)
|
||||
-> bool {
|
||||
let mut visitor = LateBoundRegionsDetector {
|
||||
tcx, binder_depth: 0, has_late_bound_regions: false
|
||||
};
|
||||
for lifetime in &generics.lifetimes {
|
||||
if tcx.named_region_map.late_bound.contains(&lifetime.lifetime.id) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
visitor.visit_fn_decl(decl);
|
||||
visitor.has_late_bound_regions
|
||||
}
|
||||
|
||||
match node {
|
||||
hir_map::NodeTraitItem(item) => match item.node {
|
||||
hir::TraitItemKind::Method(ref sig, _) =>
|
||||
has_late_bound_regions(tcx, &sig.generics, &sig.decl),
|
||||
_ => false,
|
||||
},
|
||||
hir_map::NodeImplItem(item) => match item.node {
|
||||
hir::ImplItemKind::Method(ref sig, _) =>
|
||||
has_late_bound_regions(tcx, &sig.generics, &sig.decl),
|
||||
_ => false,
|
||||
},
|
||||
hir_map::NodeForeignItem(item) => match item.node {
|
||||
hir::ForeignItemFn(ref fn_decl, _, ref generics) =>
|
||||
has_late_bound_regions(tcx, generics, fn_decl),
|
||||
_ => false,
|
||||
},
|
||||
hir_map::NodeItem(item) => match item.node {
|
||||
hir::ItemFn(ref fn_decl, .., ref generics, _) =>
|
||||
has_late_bound_regions(tcx, generics, fn_decl),
|
||||
_ => false,
|
||||
},
|
||||
_ => false
|
||||
}
|
||||
}
|
||||
|
||||
fn generics_of<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
||||
def_id: DefId)
|
||||
-> &'tcx ty::Generics {
|
||||
@ -876,13 +962,11 @@ fn generics_of<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
||||
|
||||
let has_self = opt_self.is_some();
|
||||
let mut parent_has_self = false;
|
||||
let mut parent_has_late_bound_regions = false;
|
||||
let mut own_start = has_self as u32;
|
||||
let (parent_regions, parent_types) = parent_def_id.map_or((0, 0), |def_id| {
|
||||
let generics = tcx.generics_of(def_id);
|
||||
assert_eq!(has_self, false);
|
||||
parent_has_self = generics.has_self;
|
||||
parent_has_late_bound_regions = generics.has_late_bound_regions;
|
||||
own_start = generics.count() as u32;
|
||||
(generics.parent_regions + generics.regions.len() as u32,
|
||||
generics.parent_types + generics.types.len() as u32)
|
||||
@ -900,7 +984,6 @@ fn generics_of<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
||||
}
|
||||
}).collect::<Vec<_>>();
|
||||
|
||||
let has_late_bound_regions = regions.len() != ast_generics.lifetimes.len();
|
||||
let object_lifetime_defaults =
|
||||
tcx.named_region_map.object_lifetime_defaults.get(&node_id);
|
||||
|
||||
@ -963,7 +1046,7 @@ fn generics_of<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
||||
types: types,
|
||||
type_param_to_index: type_param_to_index,
|
||||
has_self: has_self || parent_has_self,
|
||||
has_late_bound_regions: has_late_bound_regions || parent_has_late_bound_regions,
|
||||
has_late_bound_regions: has_late_bound_regions(tcx, node),
|
||||
})
|
||||
}
|
||||
|
||||
|
36
src/test/compile-fail/constructor-lifetime-args.rs
Normal file
36
src/test/compile-fail/constructor-lifetime-args.rs
Normal file
@ -0,0 +1,36 @@
|
||||
// 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.
|
||||
|
||||
// All lifetime parameters in struct constructors are currently considered early bound,
|
||||
// i.e. `S::<ARGS>` is interpreted kinda like an associated item `S::<ARGS>::ctor`.
|
||||
// This behavior is a bit weird, because if equivalent constructor were written manually
|
||||
// it would get late bound lifetime parameters.
|
||||
// Variant constructors behave in the same way, lifetime parameters are considered
|
||||
// belonging to the enum and being early bound.
|
||||
// https://github.com/rust-lang/rust/issues/30904
|
||||
|
||||
struct S<'a, 'b>(&'a u8, &'b u8);
|
||||
enum E<'a, 'b> {
|
||||
V(&'a u8),
|
||||
U(&'b u8),
|
||||
}
|
||||
|
||||
fn main() {
|
||||
S(&0, &0); // OK
|
||||
S::<'static>(&0, &0);
|
||||
//~^ ERROR expected 2 lifetime parameters, found 1 lifetime parameter
|
||||
S::<'static, 'static, 'static>(&0, &0);
|
||||
//~^ ERROR expected at most 2 lifetime parameters, found 3 lifetime parameters
|
||||
E::V(&0); // OK
|
||||
E::V::<'static>(&0);
|
||||
//~^ ERROR expected 2 lifetime parameters, found 1 lifetime parameter
|
||||
E::V::<'static, 'static, 'static>(&0);
|
||||
//~^ ERROR expected at most 2 lifetime parameters, found 3 lifetime parameters
|
||||
}
|
@ -42,25 +42,25 @@ fn method_call() {
|
||||
//~| WARN this was previously accepted
|
||||
|
||||
S.late_implicit(&0, &0); // OK
|
||||
// S.late_implicit::<'static>(&0, &0);
|
||||
//FIXME ERROR cannot specify lifetime arguments explicitly
|
||||
//FIXME WARN this was previously accepted
|
||||
// S.late_implicit::<'static, 'static>(&0, &0);
|
||||
//FIXME ERROR cannot specify lifetime arguments explicitly
|
||||
//FIXME WARN this was previously accepted
|
||||
// S.late_implicit::<'static, 'static, 'static>(&0, &0);
|
||||
//FIXME ERROR cannot specify lifetime arguments explicitly
|
||||
//FIXME WARN this was previously accepted
|
||||
S.late_implicit::<'static>(&0, &0);
|
||||
//~^ ERROR cannot specify lifetime arguments explicitly
|
||||
//~| WARN this was previously accepted
|
||||
S.late_implicit::<'static, 'static>(&0, &0);
|
||||
//~^ ERROR cannot specify lifetime arguments explicitly
|
||||
//~| WARN this was previously accepted
|
||||
S.late_implicit::<'static, 'static, 'static>(&0, &0);
|
||||
//~^ ERROR cannot specify lifetime arguments explicitly
|
||||
//~| WARN this was previously accepted
|
||||
S.late_implicit_early(&0); // OK
|
||||
S.late_implicit_early::<'static>(&0);
|
||||
//FIXME ERROR cannot specify lifetime arguments explicitly
|
||||
//FIXME WARN this was previously accepted
|
||||
// S.late_implicit_early::<'static, 'static>(&0);
|
||||
//FIXME ERROR cannot specify lifetime arguments explicitly
|
||||
//FIXME WARN this was previously accepted
|
||||
// S.late_implicit_early::<'static, 'static, 'static>(&0);
|
||||
//FIXME ERROR cannot specify lifetime arguments explicitly
|
||||
//FIXME WARN this was previously accepted
|
||||
//~^ ERROR cannot specify lifetime arguments explicitly
|
||||
//~| WARN this was previously accepted
|
||||
S.late_implicit_early::<'static, 'static>(&0);
|
||||
//~^ ERROR cannot specify lifetime arguments explicitly
|
||||
//~| WARN this was previously accepted
|
||||
S.late_implicit_early::<'static, 'static, 'static>(&0);
|
||||
//~^ ERROR cannot specify lifetime arguments explicitly
|
||||
//~| WARN this was previously accepted
|
||||
}
|
||||
|
||||
fn ufcs() {
|
||||
@ -69,8 +69,8 @@ fn ufcs() {
|
||||
//~| WARN this was previously accepted
|
||||
|
||||
S::late_implicit_early::<'static>(S, &0);
|
||||
//FIXME ERROR cannot specify lifetime arguments explicitly
|
||||
//FIXME WARN this was previously accepted
|
||||
//~^ ERROR cannot specify lifetime arguments explicitly
|
||||
//~| WARN this was previously accepted
|
||||
}
|
||||
|
||||
fn main() {}
|
||||
|
@ -16,7 +16,17 @@ impl S {
|
||||
fn early<'a, 'b>(self) -> (&'a u8, &'b u8) { loop {} }
|
||||
fn late_early<'a, 'b>(self, _: &'a u8) -> &'b u8 { loop {} }
|
||||
fn late_implicit_early<'b>(self, _: &u8) -> &'b u8 { loop {} }
|
||||
fn late_implicit_self_early<'b>(&self) -> &'b u8 { loop {} }
|
||||
fn late_unused_early<'a, 'b>(self) -> &'b u8 { loop {} }
|
||||
fn life_and_type<'a, T>(self) -> &'a T { loop {} }
|
||||
|
||||
// 'late lifetimes here belong to nested types not to the tested functions.
|
||||
fn early_tricky_explicit<'a>(_: for<'late> fn(&'late u8),
|
||||
_: Box<for<'late> Fn(&'late u8)>)
|
||||
-> &'a u8 { loop {} }
|
||||
fn early_tricky_implicit<'a>(_: fn(&u8),
|
||||
_: Box<Fn(&u8)>)
|
||||
-> &'a u8 { loop {} }
|
||||
}
|
||||
|
||||
fn method_call() {
|
||||
@ -46,21 +56,26 @@ fn ufcs() {
|
||||
|
||||
S::late_implicit(S, &0, &0); // OK
|
||||
S::late_implicit::<'static>(S, &0, &0);
|
||||
//~^ ERROR expected at most 0 lifetime parameters, found 1 lifetime parameter
|
||||
//FIXME ERROR cannot specify lifetime arguments explicitly
|
||||
//~^ ERROR cannot specify lifetime arguments explicitly
|
||||
S::late_implicit::<'static, 'static>(S, &0, &0);
|
||||
//~^ ERROR expected at most 0 lifetime parameters, found 2 lifetime parameters
|
||||
//FIXME ERROR cannot specify lifetime arguments explicitly
|
||||
//~^ ERROR cannot specify lifetime arguments explicitly
|
||||
S::late_implicit::<'static, 'static, 'static>(S, &0, &0);
|
||||
//~^ ERROR expected at most 0 lifetime parameters, found 3 lifetime parameters
|
||||
//FIXME ERROR cannot specify lifetime arguments explicitly
|
||||
//~^ ERROR cannot specify lifetime arguments explicitly
|
||||
S::late_implicit_early(S, &0); // OK
|
||||
S::late_implicit_early::<'static, 'static>(S, &0);
|
||||
//~^ ERROR expected at most 1 lifetime parameter, found 2 lifetime parameters
|
||||
//FIXME ERROR cannot specify lifetime arguments explicitly
|
||||
//~^ ERROR cannot specify lifetime arguments explicitly
|
||||
S::late_implicit_early::<'static, 'static, 'static>(S, &0);
|
||||
//~^ ERROR expected at most 1 lifetime parameter, found 3 lifetime parameters
|
||||
//FIXME ERROR cannot specify lifetime arguments explicitly
|
||||
//~^ ERROR cannot specify lifetime arguments explicitly
|
||||
S::late_implicit_self_early(&S); // OK
|
||||
S::late_implicit_self_early::<'static, 'static>(&S);
|
||||
//~^ ERROR cannot specify lifetime arguments explicitly
|
||||
S::late_implicit_self_early::<'static, 'static, 'static>(&S);
|
||||
//~^ ERROR cannot specify lifetime arguments explicitly
|
||||
S::late_unused_early(S); // OK
|
||||
S::late_unused_early::<'static, 'static>(S);
|
||||
//~^ ERROR cannot specify lifetime arguments explicitly
|
||||
S::late_unused_early::<'static, 'static, 'static>(S);
|
||||
//~^ ERROR cannot specify lifetime arguments explicitly
|
||||
|
||||
S::early(S); // OK
|
||||
S::early::<'static>(S);
|
||||
@ -70,6 +85,9 @@ fn ufcs() {
|
||||
let _: &u8 = S::life_and_type::<'static>(S);
|
||||
S::life_and_type::<u8>(S);
|
||||
S::life_and_type::<'static, u8>(S);
|
||||
|
||||
S::early_tricky_explicit::<'static>(loop {}, loop {}); // OK
|
||||
S::early_tricky_implicit::<'static>(loop {}, loop {}); // OK
|
||||
}
|
||||
|
||||
fn main() {}
|
||||
|
@ -369,7 +369,7 @@ impl Foo {
|
||||
impl Foo {
|
||||
#[rustc_dirty(label="Hir", cfg="cfail2")]
|
||||
#[rustc_clean(label="Hir", cfg="cfail3")]
|
||||
#[rustc_metadata_dirty(cfg="cfail2")]
|
||||
#[rustc_metadata_clean(cfg="cfail2")]
|
||||
#[rustc_metadata_clean(cfg="cfail3")]
|
||||
pub fn add_lifetime_parameter_to_method<'a>(&self) { }
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user