Auto merge of #50070 - toidiu:ak-2093-outlives, r=nikomatsakis

2093 infer outlives requirements

Tracking issue:  #44493
RFC: https://github.com/rust-lang/rfcs/pull/2093

- [x] add `rustc_attrs` flag
- [x] use `RequirePredicates` type
- [x]  handle explicit predicates on `dyn` Trait
- [x] handle explicit predicates on projections
- [x] more tests
- [x]  remove `unused`, `dead_code` and etc..
- [x]  documentation
This commit is contained in:
bors 2018-05-26 01:09:02 +00:00
commit 49a97ef010
45 changed files with 675 additions and 724 deletions

View file

@ -0,0 +1,67 @@
# `infer_outlives_requirements`
The tracking issue for this feature is: [#44493]
[#44493]: https://github.com/rust-lang/rust/issues/44493
------------------------
The `infer_outlives_requirements` feature indicates that certain
outlives requirements can be infered by the compiler rather than
stating them explicitly.
For example, currently generic struct definitions that contain
references, require where-clauses of the form T: 'a. By using
this feature the outlives predicates will be infered, although
they may still be written explicitly.
```rust,ignore (pseudo-Rust)
struct Foo<'a, T>
where T: 'a // <-- currently required
{
bar: &'a T,
}
```
## Examples:
```rust,ignore (pseudo-Rust)
#![feature(infer_outlives_requirements)]
// Implicitly infer T: 'a
struct Foo<'a, T> {
bar: &'a T,
}
```
```rust,ignore (pseudo-Rust)
#![feature(infer_outlives_requirements)]
// Implicitly infer `U: 'b`
struct Foo<'b, U> {
bar: Bar<'b, U>
}
struct Bar<'a, T> where T: 'a {
x: &'a (),
y: T,
}
```
```rust,ignore (pseudo-Rust)
#![feature(infer_outlives_requirements)]
// Implicitly infer `b': 'a`
struct Foo<'a, 'b, T> {
x: &'a &'b T
}
```
```rust,ignore (pseudo-Rust)
#![feature(infer_outlives_requirements)]
// Implicitly infer `<T as std::iter::Iterator>::Item : 'a`
struct Foo<'a, T: Iterator> {
bar: &'a T::Item
```

View file

@ -8,21 +8,19 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
use hir::map as hir_map;
use rustc::hir;
use rustc::hir::def_id::{CrateNum, DefId, LocalDefId, LOCAL_CRATE};
use rustc::hir::def_id::{CrateNum, DefId};
use rustc::hir::itemlikevisit::ItemLikeVisitor;
use rustc::ty::maps::Providers;
use rustc::ty::{self, CratePredicatesMap, TyCtxt};
use rustc_data_structures::sync::Lrc;
use rustc::ty::{self, TyCtxt};
use util::nodemap::FxHashMap;
use super::utils::*;
pub fn explicit_predicates<'tcx>(
tcx: TyCtxt<'_, 'tcx, 'tcx>,
crate_num: CrateNum,
) -> FxHashMap<DefId, Lrc<Vec<ty::Predicate<'tcx>>>> {
assert_eq!(crate_num, LOCAL_CRATE);
let mut predicates: FxHashMap<DefId, Lrc<Vec<ty::Predicate<'tcx>>>> = FxHashMap();
) -> FxHashMap<DefId, RequiredPredicates<'tcx>> {
let mut predicates = FxHashMap::default();
// iterate over the entire crate
tcx.hir.krate().visit_all_item_likes(&mut ExplicitVisitor {
@ -36,7 +34,7 @@ pub fn explicit_predicates<'tcx>(
pub struct ExplicitVisitor<'cx, 'tcx: 'cx> {
tcx: TyCtxt<'cx, 'tcx, 'tcx>,
explicit_predicates: &'cx mut FxHashMap<DefId, Lrc<Vec<ty::Predicate<'tcx>>>>,
explicit_predicates: &'cx mut FxHashMap<DefId, RequiredPredicates<'tcx>>,
crate_num: CrateNum,
}
@ -47,13 +45,25 @@ impl<'cx, 'tcx> ItemLikeVisitor<'tcx> for ExplicitVisitor<'cx, 'tcx> {
index: item.hir_id.owner,
};
let local_explicit_predicate = self.tcx.explicit_predicates_of(def_id);
let mut required_predicates = RequiredPredicates::default();
let local_explicit_predicate = self.tcx.explicit_predicates_of(def_id).predicates;
let filtered_predicates = local_explicit_predicate
.predicates
.into_iter()
.filter(|pred| match pred {
ty::Predicate::TypeOutlives(..) | ty::Predicate::RegionOutlives(..) => true,
for pred in local_explicit_predicate.into_iter() {
match pred {
ty::Predicate::TypeOutlives(predicate) => {
let ty::OutlivesPredicate(ref ty, ref reg) = predicate.skip_binder();
insert_outlives_predicate(self.tcx, (*ty).into(), reg, &mut required_predicates)
}
ty::Predicate::RegionOutlives(predicate) => {
let ty::OutlivesPredicate(ref reg1, ref reg2) = predicate.skip_binder();
insert_outlives_predicate(
self.tcx,
(*reg1).into(),
reg2,
&mut required_predicates,
)
}
ty::Predicate::Trait(..)
| ty::Predicate::Projection(..)
@ -61,22 +71,14 @@ impl<'cx, 'tcx> ItemLikeVisitor<'tcx> for ExplicitVisitor<'cx, 'tcx> {
| ty::Predicate::ObjectSafe(..)
| ty::Predicate::ClosureKind(..)
| ty::Predicate::Subtype(..)
| ty::Predicate::ConstEvaluatable(..) => false,
})
.collect();
match item.node {
hir::ItemStruct(..) | hir::ItemEnum(..) => {
self.tcx.adt_def(def_id);
| ty::Predicate::ConstEvaluatable(..) => (),
}
_ => {}
}
self.explicit_predicates
.insert(def_id, Lrc::new(filtered_predicates));
self.explicit_predicates.insert(def_id, required_predicates);
}
fn visit_trait_item(&mut self, trait_item: &'tcx hir::TraitItem) {}
fn visit_trait_item(&mut self, _trait_item: &'tcx hir::TraitItem) {}
fn visit_impl_item(&mut self, impl_item: &'tcx hir::ImplItem) {}
fn visit_impl_item(&mut self, _impl_item: &'tcx hir::ImplItem) {}
}

View file

@ -1,52 +0,0 @@
// Copyright 2013 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.
use hir::map as hir_map;
use rustc::hir;
use rustc::hir::def_id::{self, CrateNum, DefId, LOCAL_CRATE};
use rustc::hir::itemlikevisit::ItemLikeVisitor;
use rustc::ty::maps::Providers;
use rustc::ty::{self, CratePredicatesMap, TyCtxt};
use rustc_data_structures::sync::Lrc;
use util::nodemap::FxHashMap;
// Create the sets of inferred predicates for each type. These sets
// are initially empty but will grow during the inference step.
pub fn empty_predicate_map<'tcx>(
tcx: TyCtxt<'_, 'tcx, 'tcx>,
) -> FxHashMap<DefId, Lrc<Vec<ty::Predicate<'tcx>>>> {
let mut predicates = FxHashMap();
// iterate over the entire crate
tcx.hir
.krate()
.visit_all_item_likes(&mut EmptyImplicitVisitor {
tcx,
predicates: &mut predicates,
});
predicates
}
pub struct EmptyImplicitVisitor<'cx, 'tcx: 'cx> {
tcx: TyCtxt<'cx, 'tcx, 'tcx>,
predicates: &'cx mut FxHashMap<DefId, Lrc<Vec<ty::Predicate<'tcx>>>>,
}
impl<'a, 'p, 'v> ItemLikeVisitor<'v> for EmptyImplicitVisitor<'a, 'p> {
fn visit_item(&mut self, item: &hir::Item) {
self.predicates
.insert(self.tcx.hir.local_def_id(item.id), Lrc::new(Vec::new()));
}
fn visit_trait_item(&mut self, trait_item: &hir::TraitItem) {}
fn visit_impl_item(&mut self, impl_item: &hir::ImplItem) {}
}

View file

@ -8,24 +8,14 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
#![allow(unused)]
use rustc::hir;
use rustc::hir::def::{CtorKind, Def};
use rustc::hir::def_id::{self, CrateNum, DefId, LOCAL_CRATE};
use rustc::hir::def_id::DefId;
use rustc::hir::itemlikevisit::ItemLikeVisitor;
use rustc::hir::map as hir_map;
use rustc::ty::Slice;
use rustc::ty::maps::Providers;
use rustc::ty::outlives::Component;
use rustc::ty::subst::{Kind, Subst, UnpackedKind};
use rustc::ty::{self, AdtKind, CratePredicatesMap, Region, RegionKind, ReprOptions,
ToPolyTraitRef, ToPredicate, Ty, TyCtxt};
use rustc::util::nodemap::{FxHashMap, FxHashSet};
use rustc_data_structures::sync::Lrc;
use rustc_target::spec::abi;
use syntax::ast;
use syntax_pos::{Span, DUMMY_SP};
use rustc::ty::{self, Ty, TyCtxt};
use rustc::util::nodemap::FxHashMap;
use super::utils::*;
/// Infer predicates for the items in the crate.
///
@ -34,7 +24,7 @@ use syntax_pos::{Span, DUMMY_SP};
/// now be filled with inferred predicates.
pub fn infer_predicates<'tcx>(
tcx: TyCtxt<'_, 'tcx, 'tcx>,
explicit_map: &FxHashMap<DefId, Lrc<Vec<ty::Predicate<'tcx>>>>,
explicit_map: &FxHashMap<DefId, RequiredPredicates<'tcx>>,
) -> FxHashMap<DefId, RequiredPredicates<'tcx>> {
debug!("infer_predicates");
@ -65,20 +55,17 @@ pub struct InferVisitor<'cx, 'tcx: 'cx> {
tcx: TyCtxt<'cx, 'tcx, 'tcx>,
global_inferred_outlives: &'cx mut FxHashMap<DefId, RequiredPredicates<'tcx>>,
predicates_added: &'cx mut bool,
explicit_map: &'cx FxHashMap<DefId, Lrc<Vec<ty::Predicate<'tcx>>>>,
explicit_map: &'cx FxHashMap<DefId, RequiredPredicates<'tcx>>,
}
/// Tracks the `T: 'a` or `'a: 'a` predicates that we have inferred
/// must be added to the struct header.
type RequiredPredicates<'tcx> = FxHashSet<ty::OutlivesPredicate<Kind<'tcx>, ty::Region<'tcx>>>;
impl<'cx, 'tcx> ItemLikeVisitor<'tcx> for InferVisitor<'cx, 'tcx> {
fn visit_item(&mut self, item: &hir::Item) {
let item_did = self.tcx.hir.local_def_id(item.id);
debug!("InferVisitor::visit_item(item={:?})", item_did);
let node_id = self.tcx
let node_id = self
.tcx
.hir
.as_local_node_id(item_did)
.expect("expected local def-id");
@ -120,7 +107,8 @@ impl<'cx, 'tcx> ItemLikeVisitor<'tcx> for InferVisitor<'cx, 'tcx> {
// Therefore mark `predicates_added` as true and which will ensure
// we walk the crates again and re-calculate predicates for all
// items.
let item_predicates_len: usize = self.global_inferred_outlives
let item_predicates_len: usize = self
.global_inferred_outlives
.get(&item_did)
.map(|p| p.len())
.unwrap_or(0);
@ -131,9 +119,9 @@ impl<'cx, 'tcx> ItemLikeVisitor<'tcx> for InferVisitor<'cx, 'tcx> {
}
}
fn visit_trait_item(&mut self, trait_item: &'tcx hir::TraitItem) {}
fn visit_trait_item(&mut self, _trait_item: &'tcx hir::TraitItem) {}
fn visit_impl_item(&mut self, impl_item: &'tcx hir::ImplItem) {}
fn visit_impl_item(&mut self, _impl_item: &'tcx hir::ImplItem) {}
}
fn insert_required_predicates_to_be_wf<'tcx>(
@ -141,7 +129,7 @@ fn insert_required_predicates_to_be_wf<'tcx>(
field_ty: Ty<'tcx>,
global_inferred_outlives: &FxHashMap<DefId, RequiredPredicates<'tcx>>,
required_predicates: &mut RequiredPredicates<'tcx>,
explicit_map: &FxHashMap<DefId, Lrc<Vec<ty::Predicate<'tcx>>>>,
explicit_map: &FxHashMap<DefId, RequiredPredicates<'tcx>>,
) {
for ty in field_ty.walk() {
match ty.sty {
@ -150,6 +138,7 @@ fn insert_required_predicates_to_be_wf<'tcx>(
//
// We also want to calculate potential predicates for the T
ty::TyRef(region, rty, _) => {
debug!("TyRef");
insert_outlives_predicate(tcx, rty.into(), region, required_predicates);
}
@ -157,7 +146,6 @@ fn insert_required_predicates_to_be_wf<'tcx>(
// can load the current set of inferred and explicit
// predicates from `global_inferred_outlives` and filter the
// ones that are TypeOutlives.
//
ty::TyAdt(def, substs) => {
// First check the inferred predicates
//
@ -177,6 +165,7 @@ fn insert_required_predicates_to_be_wf<'tcx>(
// round we will get `U: 'b`. We then apply the substitution
// `['b => 'a, U => T]` and thus get the requirement that `T:
// 'a` holds for `Foo`.
debug!("TyAdt");
if let Some(unsubstituted_predicates) = global_inferred_outlives.get(&def.did) {
for unsubstituted_predicate in unsubstituted_predicates {
// `unsubstituted_predicate` is `U: 'b` in the
@ -195,33 +184,51 @@ fn insert_required_predicates_to_be_wf<'tcx>(
// Check if the type has any explicit predicates that need
// to be added to `required_predicates`
// let _: () = substs.region_at(0);
check_explicit_predicates(tcx, &def.did, substs, required_predicates, explicit_map);
check_explicit_predicates(
tcx,
&def.did,
substs,
required_predicates,
explicit_map,
false,
);
}
ty::TyDynamic(obj, region) => {
// FIXME This corresponds to `dyn Trait<..>`. In this
// case, we should use the explicit predicates as
// well.
if let Some(p) = obj.principal() {
ty::TyDynamic(obj, ..) => {
// This corresponds to `dyn Trait<..>`. In this case, we should
// use the explicit predicates as well.
// We are passing type `ty` as a placeholder value with the function
// `with_self_ty`, since there is no concrete type `Self` for a
// `dyn Trait` at this stage. Therefore when checking explicit
// predicates in `check_explicit_predicates` we need to ignore
// checking the explicit_map for Self type.
debug!("TyDynamic");
debug!("field_ty = {}", &field_ty);
debug!("ty in field = {}", &ty);
if let Some(ex_trait_ref) = obj.principal() {
check_explicit_predicates(
tcx,
&p.skip_binder().def_id,
&[region.into()],
&ex_trait_ref.skip_binder().def_id,
ex_trait_ref.with_self_ty(tcx, ty).skip_binder().substs,
required_predicates,
explicit_map,
true,
);
}
}
ty::TyProjection(obj) => {
// FIXME This corresponds to `<T as Foo<'a>>::Bar`. In this case, we should use the
// This corresponds to `<T as Foo<'a>>::Bar`. In this case, we should use the
// explicit predicates as well.
debug!("TyProjection");
check_explicit_predicates(
tcx,
&obj.item_def_id,
&tcx.associated_item(obj.item_def_id).container.id(),
obj.substs,
required_predicates,
explicit_map,
false,
);
}
@ -245,199 +252,58 @@ fn insert_required_predicates_to_be_wf<'tcx>(
/// will give us `U: 'static` and `U: Foo`. The latter we
/// can ignore, but we will want to process `U: 'static`,
/// applying the substitution as above.
fn check_explicit_predicates<'tcx>(
pub fn check_explicit_predicates<'tcx>(
tcx: TyCtxt<'_, 'tcx, 'tcx>,
def_id: &DefId,
substs: &[Kind<'tcx>],
required_predicates: &mut RequiredPredicates<'tcx>,
explicit_map: &FxHashMap<DefId, Lrc<Vec<ty::Predicate<'tcx>>>>,
explicit_map: &FxHashMap<DefId, RequiredPredicates<'tcx>>,
ignore_self_ty: bool,
) {
if let Some(general_predicates) = explicit_map.get(def_id) {
for general_predicate in general_predicates.iter() {
match general_predicate {
// `poly` is `PolyTypeOutlivesPredicate<OutlivesPredicate<Ty>>`
// where OutlivesPredicate<type1, region1> is the predicate
// we want to add.
ty::Predicate::TypeOutlives(poly) => {
let predicate = poly.skip_binder().subst(tcx, substs);
insert_outlives_predicate(
tcx,
predicate.0.into(),
predicate.1,
required_predicates,
);
}
debug!("def_id = {:?}", &def_id);
debug!("substs = {:?}", &substs);
debug!("explicit_map = {:?}", explicit_map);
debug!("required_predicates = {:?}", required_predicates);
if let Some(explicit_predicates) = explicit_map.get(def_id) {
for outlives_predicate in explicit_predicates.iter() {
debug!("outlives_predicate = {:?}", &outlives_predicate);
// `poly` is `PolyRegionOutlivesPredicate<OutlivesPredicate<Ty>>`
// where OutlivesPredicate<region1, region2> is the predicate
// we want to add.
ty::Predicate::RegionOutlives(poly) => {
let predicate = poly.skip_binder().subst(tcx, substs);
insert_outlives_predicate(
tcx,
predicate.0.into(),
predicate.1,
required_predicates,
);
}
ty::Predicate::Trait(..)
| ty::Predicate::Projection(..)
| ty::Predicate::WellFormed(..)
| ty::Predicate::ObjectSafe(..)
| ty::Predicate::ClosureKind(..)
| ty::Predicate::Subtype(..)
| ty::Predicate::ConstEvaluatable(..) => (),
}
}
}
}
/// Given a requirement `T: 'a` or `'b: 'a`, deduce the
/// outlives_component and add it to `required_predicates`
fn insert_outlives_predicate<'tcx>(
tcx: TyCtxt<'_, 'tcx, 'tcx>,
kind: Kind<'tcx>,
outlived_region: Region<'tcx>,
required_predicates: &mut RequiredPredicates<'tcx>,
) {
// If the `'a` region is bound within the field type itself, we
// don't want to propagate this constraint to the header.
if !is_free_region(outlived_region) {
return;
}
match kind.unpack() {
UnpackedKind::Type(ty) => {
// `T: 'outlived_region` for some type `T`
// But T could be a lot of things:
// e.g., if `T = &'b u32`, then `'b: 'outlived_region` is
// what we want to add.
// Careful: If we are inferring the effects of a `dyn Trait<..>`
// type, then when we look up the predicates for `Trait`,
// we may find some that reference `Self`. e.g., perhaps the
// definition of `Trait` was:
//
// Or if within `struct Foo<U>` you had `T = Vec<U>`, then
// we would want to add `U: 'outlived_region`
for component in tcx.outlives_components(ty) {
match component {
Component::Region(r) => {
// This would arise from something like:
//
// ```
// struct Foo<'a, 'b> {
// x: &'a &'b u32
// }
// ```
//
// Here `outlived_region = 'a` and `kind = &'b
// u32`. Decomposing `&'b u32` into
// components would yield `'b`, and we add the
// where clause that `'b: 'a`.
insert_outlives_predicate(
tcx,
r.into(),
outlived_region,
required_predicates,
);
}
Component::Param(param_ty) => {
// param_ty: ty::ParamTy
// This would arise from something like:
//
// ```
// struct Foo<'a, U> {
// x: &'a Vec<U>
// }
// ```
//
// Here `outlived_region = 'a` and `kind =
// Vec<U>`. Decomposing `Vec<U>` into
// components would yield `U`, and we add the
// where clause that `U: 'a`.
let ty: Ty<'tcx> = tcx.mk_ty_param(param_ty.idx, param_ty.name);
required_predicates
.insert(ty::OutlivesPredicate(ty.into(), outlived_region));
}
Component::Projection(proj_ty) => {
// This would arise from something like:
//
// ```
// struct Foo<'a, T: Iterator> {
// x: &'a <T as Iterator>::Item
// }
// ```
//
// Here we want to add an explicit `where <T as Iterator>::Item: 'a`.
let ty: Ty<'tcx> = tcx.mk_projection(proj_ty.item_def_id, proj_ty.substs);
required_predicates
.insert(ty::OutlivesPredicate(ty.into(), outlived_region));
}
Component::EscapingProjection(_) => {
// As above, but the projection involves
// late-bound regions. Therefore, the WF
// requirement is not checked in type definition
// but at fn call site, so ignore it.
//
// ```
// struct Foo<'a, T: Iterator> {
// x: for<'b> fn(<&'b T as Iterator>::Item)
// // ^^^^^^^^^^^^^^^^^^^^^^^^^
// }
// ```
//
// Since `'b` is not in scope on `Foo`, can't
// do anything here, ignore it.
}
Component::UnresolvedInferenceVariable(_) => bug!("not using infcx"),
// ```
// trait Trait<'a, T> where Self: 'a { .. }
// ```
//
// we want to ignore such predicates here, because
// there is no type parameter for them to affect. Consider
// a struct containing `dyn Trait`:
//
// ```
// struct MyStruct<'x, X> { field: Box<dyn Trait<'x, X>> }
// ```
//
// The `where Self: 'a` predicate refers to the *existential, hidden type*
// that is represented by the `dyn Trait`, not to the `X` type parameter
// (or any other generic parameter) declared on `MyStruct`.
//
// Note that we do this check for self **before** applying `substs`. In the
// case that `substs` come from a `dyn Trait` type, our caller will have
// included `Self = dyn Trait<'x, X>` as the value for `Self`. If we were
// to apply the substs, and not filter this predicate, we might then falsely
// conclude that e.g. `X: 'x` was a reasonable inferred requirement.
if let UnpackedKind::Type(ty) = outlives_predicate.0.unpack() {
if ty.is_self() && ignore_self_ty {
debug!("skipping self ty = {:?}", &ty);
continue;
}
}
}
UnpackedKind::Lifetime(r) => {
if !is_free_region(r) {
return;
}
required_predicates.insert(ty::OutlivesPredicate(kind, outlived_region));
}
}
}
fn is_free_region(region: Region<'_>) -> bool {
// First, screen for regions that might appear in a type header.
match region {
// *These* correspond to `T: 'a` relationships where `'a` is
// either declared on the type or `'static`:
//
// struct Foo<'a, T> {
// field: &'a T, // this would generate a ReEarlyBound referencing `'a`
// field2: &'static T, // this would generate a ReStatic
// }
//
// We care about these, so fall through.
RegionKind::ReStatic | RegionKind::ReEarlyBound(_) => true,
// Late-bound regions can appear in `fn` types:
//
// struct Foo<T> {
// field: for<'b> fn(&'b T) // e.g., 'b here
// }
//
// The type above might generate a `T: 'b` bound, but we can
// ignore it. We can't put it on the struct header anyway.
RegionKind::ReLateBound(..) => false,
// These regions don't appear in types from type declarations:
RegionKind::ReEmpty
| RegionKind::ReErased
| RegionKind::ReClosureBound(..)
| RegionKind::ReCanonical(..)
| RegionKind::ReScope(..)
| RegionKind::ReVar(..)
| RegionKind::ReSkolemized(..)
| RegionKind::ReFree(..) => {
bug!("unexpected region in outlives inference: {:?}", region);
let predicate = outlives_predicate.subst(tcx, substs);
debug!("predicate = {:?}", &predicate);
insert_outlives_predicate(tcx, predicate.0.into(), predicate.1, required_predicates);
}
}
}

View file

@ -7,24 +7,20 @@
// <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.
#![allow(unused)]
#[allow(dead_code)]
use hir::map as hir_map;
use rustc::dep_graph::DepKind;
use rustc::hir;
use rustc::hir::Ty_::*;
use rustc::hir::def_id::{CrateNum, DefId, LOCAL_CRATE};
use rustc::ty::maps::Providers;
use rustc::ty::subst::UnpackedKind;
use rustc::ty::{self, CratePredicatesMap, TyCtxt};
use rustc_data_structures::sync::Lrc;
use util::nodemap::FxHashMap;
mod explicit;
mod implicit_empty;
mod implicit_infer;
/// Code to write unit test for outlives.
pub mod test;
mod utils;
pub fn provide(providers: &mut Providers) {
*providers = Providers {
@ -38,7 +34,8 @@ fn inferred_outlives_of<'a, 'tcx>(
tcx: TyCtxt<'a, 'tcx, 'tcx>,
item_def_id: DefId,
) -> Lrc<Vec<ty::Predicate<'tcx>>> {
let id = tcx.hir
let id = tcx
.hir
.as_local_node_id(item_def_id)
.expect("expected local def-id");
@ -46,14 +43,34 @@ fn inferred_outlives_of<'a, 'tcx>(
hir_map::NodeItem(item) => match item.node {
hir::ItemStruct(..) | hir::ItemEnum(..) | hir::ItemUnion(..) => {
let crate_map = tcx.inferred_outlives_crate(LOCAL_CRATE);
let dep_node = item_def_id.to_dep_node(tcx, DepKind::InferredOutlivesOf);
tcx.dep_graph.read(dep_node);
crate_map
let predicates = crate_map
.predicates
.get(&item_def_id)
.unwrap_or(&crate_map.empty_predicate)
.clone()
.clone();
if tcx.has_attr(item_def_id, "rustc_outlives") {
let mut pred: Vec<String> = predicates
.iter()
.map(|out_pred| match out_pred {
ty::Predicate::RegionOutlives(p) => format!("{}", &p),
ty::Predicate::TypeOutlives(p) => format!("{}", &p),
err => bug!("unexpected predicate {:?}", err),
})
.collect();
pred.sort();
let span = tcx.def_span(item_def_id);
let mut err = tcx.sess.struct_span_err(span, "rustc_outlives");
for p in &pred {
err.note(p);
}
err.emit();
}
predicates
}
_ => Lrc::new(Vec::new()),
@ -76,17 +93,18 @@ fn inferred_outlives_crate<'tcx>(
// Compute the inferred predicates
let exp = explicit::explicit_predicates(tcx, crate_num);
let mut global_inferred_outlives = implicit_infer::infer_predicates(tcx, &exp);
let global_inferred_outlives = implicit_infer::infer_predicates(tcx, &exp);
// Convert the inferred predicates into the "collected" form the
// global data structure expects.
//
// FIXME -- consider correcting impedance mismatch in some way,
// probably by updating the global data structure.
let mut predicates = global_inferred_outlives
let predicates = global_inferred_outlives
.iter()
.map(|(&def_id, set)| {
let vec: Vec<ty::Predicate<'tcx>> = set.iter()
let vec: Vec<ty::Predicate<'tcx>> = set
.iter()
.map(
|ty::OutlivesPredicate(kind1, region2)| match kind1.unpack() {
UnpackedKind::Type(ty1) => ty::Predicate::TypeOutlives(ty::Binder::bind(

View file

@ -0,0 +1,167 @@
// Copyright 2013 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.
use rustc::ty::outlives::Component;
use rustc::ty::subst::{Kind, UnpackedKind};
use rustc::ty::{self, Region, RegionKind, Ty, TyCtxt};
use std::collections::BTreeSet;
/// Tracks the `T: 'a` or `'a: 'a` predicates that we have inferred
/// must be added to the struct header.
pub type RequiredPredicates<'tcx> = BTreeSet<ty::OutlivesPredicate<Kind<'tcx>, ty::Region<'tcx>>>;
/// Given a requirement `T: 'a` or `'b: 'a`, deduce the
/// outlives_component and add it to `required_predicates`
pub fn insert_outlives_predicate<'tcx>(
tcx: TyCtxt<'_, 'tcx, 'tcx>,
kind: Kind<'tcx>,
outlived_region: Region<'tcx>,
required_predicates: &mut RequiredPredicates<'tcx>,
) {
// If the `'a` region is bound within the field type itself, we
// don't want to propagate this constraint to the header.
if !is_free_region(outlived_region) {
return;
}
match kind.unpack() {
UnpackedKind::Type(ty) => {
// `T: 'outlived_region` for some type `T`
// But T could be a lot of things:
// e.g., if `T = &'b u32`, then `'b: 'outlived_region` is
// what we want to add.
//
// Or if within `struct Foo<U>` you had `T = Vec<U>`, then
// we would want to add `U: 'outlived_region`
for component in tcx.outlives_components(ty) {
match component {
Component::Region(r) => {
// This would arise from something like:
//
// ```
// struct Foo<'a, 'b> {
// x: &'a &'b u32
// }
// ```
//
// Here `outlived_region = 'a` and `kind = &'b
// u32`. Decomposing `&'b u32` into
// components would yield `'b`, and we add the
// where clause that `'b: 'a`.
insert_outlives_predicate(
tcx,
r.into(),
outlived_region,
required_predicates,
);
}
Component::Param(param_ty) => {
// param_ty: ty::ParamTy
// This would arise from something like:
//
// ```
// struct Foo<'a, U> {
// x: &'a Vec<U>
// }
// ```
//
// Here `outlived_region = 'a` and `kind =
// Vec<U>`. Decomposing `Vec<U>` into
// components would yield `U`, and we add the
// where clause that `U: 'a`.
let ty: Ty<'tcx> = param_ty.to_ty(tcx);
required_predicates
.insert(ty::OutlivesPredicate(ty.into(), outlived_region));
}
Component::Projection(proj_ty) => {
// This would arise from something like:
//
// ```
// struct Foo<'a, T: Iterator> {
// x: &'a <T as Iterator>::Item
// }
// ```
//
// Here we want to add an explicit `where <T as Iterator>::Item: 'a`.
let ty: Ty<'tcx> = tcx.mk_projection(proj_ty.item_def_id, proj_ty.substs);
required_predicates
.insert(ty::OutlivesPredicate(ty.into(), outlived_region));
}
Component::EscapingProjection(_) => {
// As above, but the projection involves
// late-bound regions. Therefore, the WF
// requirement is not checked in type definition
// but at fn call site, so ignore it.
//
// ```
// struct Foo<'a, T: Iterator> {
// x: for<'b> fn(<&'b T as Iterator>::Item)
// // ^^^^^^^^^^^^^^^^^^^^^^^^^
// }
// ```
//
// Since `'b` is not in scope on `Foo`, can't
// do anything here, ignore it.
}
Component::UnresolvedInferenceVariable(_) => bug!("not using infcx"),
}
}
}
UnpackedKind::Lifetime(r) => {
if !is_free_region(r) {
return;
}
required_predicates.insert(ty::OutlivesPredicate(kind, outlived_region));
}
}
}
fn is_free_region(region: Region<'_>) -> bool {
// First, screen for regions that might appear in a type header.
match region {
// *These* correspond to `T: 'a` relationships where `'a` is
// either declared on the type or `'static`:
//
// struct Foo<'a, T> {
// field: &'a T, // this would generate a ReEarlyBound referencing `'a`
// field2: &'static T, // this would generate a ReStatic
// }
//
// We care about these, so fall through.
RegionKind::ReStatic | RegionKind::ReEarlyBound(_) => true,
// Late-bound regions can appear in `fn` types:
//
// struct Foo<T> {
// field: for<'b> fn(&'b T) // e.g., 'b here
// }
//
// The type above might generate a `T: 'b` bound, but we can
// ignore it. We can't put it on the struct header anyway.
RegionKind::ReLateBound(..) => false,
// These regions don't appear in types from type declarations:
RegionKind::ReEmpty
| RegionKind::ReErased
| RegionKind::ReClosureBound(..)
| RegionKind::ReCanonical(..)
| RegionKind::ReScope(..)
| RegionKind::ReVar(..)
| RegionKind::ReSkolemized(..)
| RegionKind::ReFree(..) => {
bug!("unexpected region in outlives inference: {:?}", region);
}
}
}

View file

@ -795,6 +795,12 @@ pub const BUILTIN_ATTRIBUTES: &'static [(&'static str, AttributeType, AttributeG
attribute is an experimental \
feature",
cfg_fn!(needs_panic_runtime))),
("rustc_outlives", Normal, Gated(Stability::Unstable,
"rustc_attrs",
"the `#[rustc_outlives]` attribute \
is just used for rustc unit tests \
and will never be stable",
cfg_fn!(rustc_attrs))),
("rustc_variance", Normal, Gated(Stability::Unstable,
"rustc_attrs",
"the `#[rustc_variance]` attribute \

View file

@ -1,25 +0,0 @@
// Copyright 2015 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.
// ignore-tidy-linelength
// Test that the outlives computation runs for now...
#![feature(rustc_attrs)]
//todo add all the test cases
// https://github.com/rust-lang/rfcs/blob/master/text/2093-infer-outlives.md#example-1-a-reference
#[rustc_outlives]
struct Direct<'a, T> { //~ ERROR 21:1: 23:2: [Binder(OutlivesPredicate(T, ReEarlyBound(0, 'a)))] [E0640]
field: &'a T
}
fn main() { }

View file

@ -8,12 +8,17 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
// Needs an explicit where clause stating outlives condition. (RFC 2093)
#![feature(dyn_trait)]
#![feature(rustc_attrs)]
#![feature(infer_outlives_requirements)]
// Lifetime 'b needs to outlive lifetime 'a
struct Foo<'a,'b,T> {
x: &'a &'b T //~ ERROR reference has a longer lifetime than the data it references [E0491]
trait Trait<'x, T> where T: 'x {
}
#[rustc_outlives]
struct Foo<'a, A> //~ ERROR 19:1: 22:2: rustc_outlives
{
foo: Box<dyn Trait<'a, A>>
}
fn main() {}

View file

@ -0,0 +1,13 @@
error: rustc_outlives
--> $DIR/explicit-dyn.rs:19:1
|
LL | / struct Foo<'a, A> //~ ERROR 19:1: 22:2: rustc_outlives
LL | | {
LL | | foo: Box<dyn Trait<'a, A>>
LL | | }
| |_^
|
= note: A : 'a
error: aborting due to previous error

View file

@ -8,16 +8,18 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
// compile-pass
#![feature(rustc_attrs)]
#![feature(infer_outlives_requirements)]
// Outlives requirementes are inferred (RFC 2093)
// projections: infer <Iterator>::Item: 'a
struct ProjFoo<'a, T: Iterator> {
bar: &'a T::Item
#[rustc_outlives]
enum Foo<'a, U> { //~ ERROR 15:1: 17:2: rustc_outlives
One(Bar<'a, U>)
}
struct Bar<'x, T> where T: 'x {
x: &'x (),
y: T,
}
fn main() {}

View file

@ -0,0 +1,12 @@
error: rustc_outlives
--> $DIR/explicit-enum.rs:15:1
|
LL | / enum Foo<'a, U> { //~ ERROR 15:1: 17:2: rustc_outlives
LL | | One(Bar<'a, U>)
LL | | }
| |_^
|
= note: U : 'a
error: aborting due to previous error

View file

@ -1,30 +0,0 @@
// Copyright 2015 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.
// ignore-test
// compile-pass
#![feature(infer_outlives_requirements)]
// Outlives requirementes are inferred (RFC 2093)
trait MakeRef<'a>: 'a {
type Type;
}
impl<'a, T> MakeRef<'a> for Vec<T>
where T: 'a,
{
type Type = &'a T;
}
// explicit-impl: T: 'a
struct Foo<'a, T> {
foo: <Vec<T> as MakeRef<'a>>::Type,
}
fn main() {}

View file

@ -1,30 +0,0 @@
// Copyright 2015 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.
// ignore-test
// compile-pass
#![feature(infer_outlives_requirements)]
// Outlives requirementes are inferred (RFC 2093)
trait MakeRef<'a> {
type Type;
}
impl<'a, T> MakeRef<'a> for Vec<T>
where T: 'a,
{
type Type = &'a T;
}
// explicit-impl: T: 'a
struct Foo<'a, T> {
foo: <Vec<T> as MakeRef<'a>>::Type,
}
fn main() {}

View file

@ -1,30 +0,0 @@
// Copyright 2015 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.
// ignore-tidy-linelength
// Needs an explicit where clause stating outlives condition. (RFC 2093)
trait MakeRef<'a> {
type Type;
}
impl<'a, T> MakeRef<'a> for Vec<T>
where T: 'a
{
type Type = &'a T;
}
// Type T needs to outlive lifetime 'a, as stated in impl.
struct Foo<'a, T> {
foo: <Vec<T> as MakeRef<'a>>::Type //~ Error the parameter type `T` may not live long enough [E0309]
}
fn main() { }

View file

@ -1,17 +0,0 @@
error[E0309]: the parameter type `T` may not live long enough
--> $DIR/explicit-impl.rs:27:5
|
LL | struct Foo<'a, T> {
| - help: consider adding an explicit lifetime bound `T: 'a`...
LL | foo: <Vec<T> as MakeRef<'a>>::Type //~ Error the parameter type `T` may not live long enough [E0309]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
note: ...so that the type `T` will meet its required lifetime bounds
--> $DIR/explicit-impl.rs:27:5
|
LL | foo: <Vec<T> as MakeRef<'a>>::Type //~ Error the parameter type `T` may not live long enough [E0309]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: aborting due to previous error
For more information about this error, try `rustc --explain E0309`.

View file

@ -0,0 +1,24 @@
// 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.
#![feature(rustc_attrs)]
#![feature(infer_outlives_requirements)]
trait Trait<'x, T> where T: 'x {
type Type;
}
#[rustc_outlives]
struct Foo<'a, A, B> where A: Trait<'a, B> //~ ERROR rustc_outlives
{
foo: <A as Trait<'a, B>>::Type
}
fn main() {}

View file

@ -0,0 +1,13 @@
error: rustc_outlives
--> $DIR/explicit-projection.rs:19:1
|
LL | / struct Foo<'a, A, B> where A: Trait<'a, B> //~ ERROR rustc_outlives
LL | | {
LL | | foo: <A as Trait<'a, B>>::Type
LL | | }
| |_^
|
= note: B : 'a
error: aborting due to previous error

View file

@ -8,20 +8,18 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
// compile-pass
#![feature(rustc_attrs)]
#![feature(infer_outlives_requirements)]
// Outlives requirementes are inferred (RFC 2093)
// explicit-where: infer U: 'b
struct ExFoo<'b, U> {
bar: ExBar<'b, U>
#[rustc_outlives]
struct Foo<'b, U> { //~ ERROR 15:1: 17:2: rustc_outlives
bar: Bar<'b, U>
}
struct ExBar<'a, T> where T: 'a {
struct Bar<'a, T> where T: 'a {
x: &'a (),
y: T,
}
fn main() {}

View file

@ -0,0 +1,12 @@
error: rustc_outlives
--> $DIR/explicit-struct.rs:15:1
|
LL | / struct Foo<'b, U> { //~ ERROR 15:1: 17:2: rustc_outlives
LL | | bar: Bar<'b, U>
LL | | }
| |_^
|
= note: U : 'b
error: aborting due to previous error

View file

@ -8,17 +8,20 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
// compile-pass
#![feature(rustc_attrs)]
#![feature(infer_outlives_requirements)]
// Outlives requirementes are inferred (RFC 2093)
#![feature(untagged_unions)]
#![allow(unions_with_drop_fields)]
// nested-structs: infer U: 'b and therefore T: 'a
struct NestFoo<'a, T> {
field1: NestBar<'a, T>
#[rustc_outlives]
union Foo<'b, U> { //~ ERROR 18:1: 20:2: rustc_outlives
bar: Bar<'b, U>
}
struct NestBar<'b, U> {
field2: &'b U
union Bar<'a, T> where T: 'a {
x: &'a (),
y: T,
}
fn main() {}

View file

@ -0,0 +1,12 @@
error: rustc_outlives
--> $DIR/explicit-union.rs:18:1
|
LL | / union Foo<'b, U> { //~ ERROR 18:1: 20:2: rustc_outlives
LL | | bar: Bar<'b, U>
LL | | }
| |_^
|
= note: U : 'b
error: aborting due to previous error

View file

@ -1,23 +0,0 @@
// Copyright 2015 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.
// Needs an explicit where clause stating outlives condition. (RFC 2093)
// Type U needs to outlive lifetime 'b.
struct Foo<'b, U> {
bar: Bar<'b, U> //~ Error the parameter type `U` may not live long enough [E0309]
}
struct Bar<'a, T> where T: 'a {
x: &'a (),
y: T,
}
fn main() { }

View file

@ -1,17 +0,0 @@
error[E0309]: the parameter type `U` may not live long enough
--> $DIR/explicit-where.rs:15:5
|
LL | struct Foo<'b, U> {
| - help: consider adding an explicit lifetime bound `U: 'b`...
LL | bar: Bar<'b, U> //~ Error the parameter type `U` may not live long enough [E0309]
| ^^^^^^^^^^^^^^^
|
note: ...so that the type `U` will meet its required lifetime bounds
--> $DIR/explicit-where.rs:15:5
|
LL | bar: Bar<'b, U> //~ Error the parameter type `U` may not live long enough [E0309]
| ^^^^^^^^^^^^^^^
error: aborting due to previous error
For more information about this error, try `rustc --explain E0309`.

View file

@ -1,20 +0,0 @@
error[E0491]: in type `&'a &'b T`, reference has a longer lifetime than the data it references
--> $DIR/multiple-regions.rs:15:5
|
LL | x: &'a &'b T //~ ERROR reference has a longer lifetime than the data it references [E0491]
| ^^^^^^^^^^^^
|
note: the pointer is valid for the lifetime 'a as defined on the struct at 14:1
--> $DIR/multiple-regions.rs:14:1
|
LL | struct Foo<'a,'b,T> {
| ^^^^^^^^^^^^^^^^^^^
note: but the referenced data is only valid for the lifetime 'b as defined on the struct at 14:1
--> $DIR/multiple-regions.rs:14:1
|
LL | struct Foo<'a,'b,T> {
| ^^^^^^^^^^^^^^^^^^^
error: aborting due to previous error
For more information about this error, try `rustc --explain E0491`.

View file

@ -8,31 +8,18 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
// compile-pass
#![feature(rustc_attrs)]
#![feature(infer_outlives_requirements)]
// Type T needs to outlive lifetime 'a.
enum Foo<'a, T> {
#[rustc_outlives]
enum Foo<'a, T> { //~ ERROR 16:1: 19:2: rustc_outlives
One(Bar<'a, T>)
}
// Type U needs to outlive lifetime 'b
struct Bar<'b, U> {
field2: &'b U
}
// Type K needs to outlive lifetime 'c.
enum Ying<'c, K> {
One(&'c Yang<K>)
}
struct Yang<V> {
field2: V
}
fn main() {}

View file

@ -0,0 +1,13 @@
error: rustc_outlives
--> $DIR/nested-enum.rs:16:1
|
LL | / enum Foo<'a, T> { //~ ERROR 16:1: 19:2: rustc_outlives
LL | |
LL | | One(Bar<'a, T>)
LL | | }
| |_^
|
= note: T : 'a
error: aborting due to previous error

View file

@ -8,15 +8,12 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
// compile-pass
#![feature(rustc_attrs)]
#![feature(infer_outlives_requirements)]
// Outlives requirementes are inferred (RFC 2093)
// multiple-regions: infer 'b: 'a
struct MultiFoo<'a, 'b, T> {
#[rustc_outlives]
struct Foo<'a, 'b, T> { //~ ERROR 15:1: 17:2: rustc_outlives
x: &'a &'b T
}
fn main() {}

View file

@ -0,0 +1,14 @@
error: rustc_outlives
--> $DIR/nested-regions.rs:15:1
|
LL | / struct Foo<'a, 'b, T> { //~ ERROR 15:1: 17:2: rustc_outlives
LL | | x: &'a &'b T
LL | | }
| |_^
|
= note: 'b : 'a
= note: T : 'a
= note: T : 'b
error: aborting due to previous error

View file

@ -1,4 +1,4 @@
// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
@ -8,19 +8,16 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
// Needs an explicit where clause stating outlives condition. (RFC 2093)
#![feature(rustc_attrs)]
#![feature(infer_outlives_requirements)]
// Type T needs to outlive lifetime 'a. This is not reported due to
// a compilation error in Bar.
struct Foo<'a, T> {
#[rustc_outlives]
struct Foo<'a, T> { //~ ERROR 15:1: 17:2: rustc_outlives
field1: Bar<'a, T>
}
// Type U needs to outlive lifetime 'b
struct Bar<'b, U> {
field2: &'b U //~ ERROR the parameter type `U` may not live long enough [E0309]
field2: &'b U
}
fn main() {}

View file

@ -1,17 +1,12 @@
error[E0309]: the parameter type `U` may not live long enough
--> $DIR/nested-structs.rs:22:5
error: rustc_outlives
--> $DIR/nested-structs.rs:15:1
|
LL | struct Bar<'b, U> {
| - help: consider adding an explicit lifetime bound `U: 'b`...
LL | field2: &'b U //~ ERROR the parameter type `U` may not live long enough [E0309]
| ^^^^^^^^^^^^^
LL | / struct Foo<'a, T> { //~ ERROR 15:1: 17:2: rustc_outlives
LL | | field1: Bar<'a, T>
LL | | }
| |_^
|
note: ...so that the reference type `&'b U` does not outlive the data it points at
--> $DIR/nested-structs.rs:22:5
|
LL | field2: &'b U //~ ERROR the parameter type `U` may not live long enough [E0309]
| ^^^^^^^^^^^^^
= note: T : 'a
error: aborting due to previous error
For more information about this error, try `rustc --explain E0309`.

View file

@ -8,15 +8,14 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
// compile-pass
#![feature(rustc_attrs)]
#![feature(infer_outlives_requirements)]
#![feature(untagged_unions)]
#![allow(unions_with_drop_fields)]
// Type T needs to outlive lifetime 'a. This is not reported due to
// a compilation error in Bar.
union Foo<'a, T> {
#[rustc_outlives]
union Foo<'a, T> { //~ ERROR 18:1: 20:2: rustc_outlives
field1: Bar<'a, T>
}
@ -25,15 +24,4 @@ union Bar<'b, U> {
field2: &'b U
}
// Type K needs to outlive lifetime 'c.
union Ying<'c, K> {
field1: &'c Yang<K>
}
union Yang<V> {
field2: V
}
fn main() {}

View file

@ -0,0 +1,12 @@
error: rustc_outlives
--> $DIR/nested-union.rs:18:1
|
LL | / union Foo<'a, T> { //~ ERROR 18:1: 20:2: rustc_outlives
LL | | field1: Bar<'a, T>
LL | | }
| |_^
|
= note: T : 'a
error: aborting due to previous error

View file

@ -8,16 +8,13 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
// compile-pass
#![feature(rustc_attrs)]
#![feature(infer_outlives_requirements)]
// Outlives requirementes are inferred (RFC 2093)
// reference: infer T: 'a
struct RefFoo<'a, T> {
bar: &'a [T]
#[rustc_outlives]
struct Foo<'a, T: Iterator> { //~ ERROR rustc_outlives
bar: &'a T::Item
}
fn main() {}

View file

@ -0,0 +1,12 @@
error: rustc_outlives
--> $DIR/projection.rs:15:1
|
LL | / struct Foo<'a, T: Iterator> { //~ ERROR rustc_outlives
LL | | bar: &'a T::Item
LL | | }
| |_^
|
= note: <T as std::iter::Iterator>::Item : 'a
error: aborting due to previous error

View file

@ -1,20 +0,0 @@
// Copyright 2015 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.
// ignore-tidy-linelength
// Needs an explicit where clause stating outlives condition. RFC 2093
// Associated type <Iterator>::Item needs to outlives lifetime 'a.
struct Foo<'a, T: Iterator> {
bar: &'a T::Item //~ Error the associated type `<T as std::iter::Iterator>::Item` may not live long enough [E0309]
}
fn main() { }

View file

@ -1,16 +0,0 @@
error[E0309]: the associated type `<T as std::iter::Iterator>::Item` may not live long enough
--> $DIR/projections.rs:17:5
|
LL | bar: &'a T::Item //~ Error the associated type `<T as std::iter::Iterator>::Item` may not live long enough [E0309]
| ^^^^^^^^^^^^^^^^
|
= help: consider adding an explicit lifetime bound `<T as std::iter::Iterator>::Item: 'a`...
note: ...so that the reference type `&'a <T as std::iter::Iterator>::Item` does not outlive the data it points at
--> $DIR/projections.rs:17:5
|
LL | bar: &'a T::Item //~ Error the associated type `<T as std::iter::Iterator>::Item` may not live long enough [E0309]
| ^^^^^^^^^^^^^^^^
error: aborting due to previous error
For more information about this error, try `rustc --explain E0309`.

View file

@ -1,4 +1,4 @@
// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
// 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.
//
@ -8,11 +8,12 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
// Needs an explicit where clause stating outlives condition. (RFC 2093)
#![feature(rustc_attrs)]
#![feature(infer_outlives_requirements)]
// Type T needs to outlive lifetime 'a.
struct Foo<'a, T> {
bar: &'a [T] //~ ERROR the parameter type `T` may not live long enough [E0309]
#[rustc_outlives]
struct Foo<'a, T> { //~ ERROR rustc_outlives
bar: &'a T,
}
fn main() { }
fn main() {}

View file

@ -1,17 +1,12 @@
error[E0309]: the parameter type `T` may not live long enough
--> $DIR/reference.rs:15:5
error: rustc_outlives
--> $DIR/reference.rs:15:1
|
LL | struct Foo<'a, T> {
| - help: consider adding an explicit lifetime bound `T: 'a`...
LL | bar: &'a [T] //~ ERROR the parameter type `T` may not live long enough [E0309]
| ^^^^^^^^^^^^
LL | / struct Foo<'a, T> { //~ ERROR rustc_outlives
LL | | bar: &'a T,
LL | | }
| |_^
|
note: ...so that the reference type `&'a [T]` does not outlive the data it points at
--> $DIR/reference.rs:15:5
|
LL | bar: &'a [T] //~ ERROR the parameter type `T` may not live long enough [E0309]
| ^^^^^^^^^^^^
= note: T : 'a
error: aborting due to previous error
For more information about this error, try `rustc --explain E0309`.

View file

@ -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.
#![feature(dyn_trait)]
#![feature(rustc_attrs)]
#![feature(infer_outlives_requirements)]
trait Trait<'x, 's, T> where T: 'x,
's: {
}
#[rustc_outlives]
struct Foo<'a, 'b, A> //~ ERROR 20:1: 23:2: rustc_outlives
{
foo: Box<dyn Trait<'a, 'b, A>>
}
fn main() {}

View file

@ -0,0 +1,13 @@
error: rustc_outlives
--> $DIR/self-dyn.rs:20:1
|
LL | / struct Foo<'a, 'b, A> //~ ERROR 20:1: 23:2: rustc_outlives
LL | | {
LL | | foo: Box<dyn Trait<'a, 'b, A>>
LL | | }
| |_^
|
= note: A : 'a
error: aborting due to previous error

View file

@ -0,0 +1,24 @@
// Copyright 2015 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.
#![feature(rustc_attrs)]
#![feature(infer_outlives_requirements)]
#[rustc_outlives]
struct Foo<'a, 'b, T> { //~ ERROR 15:1: 17:2: rustc_outlives
field1: Bar<'a, 'b, T>
}
trait Bar<'x, 's, U>
where U: 'x,
Self:'s
{}
fn main() {}

View file

@ -0,0 +1,12 @@
error: rustc_outlives
--> $DIR/self-structs.rs:15:1
|
LL | / struct Foo<'a, 'b, T> { //~ ERROR 15:1: 17:2: rustc_outlives
LL | | field1: Bar<'a, 'b, T>
LL | | }
| |_^
|
= note: T : 'a
error: aborting due to previous error

View file

@ -1,40 +0,0 @@
// 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.
// ignore-tidy-linelength
// Needs an explicit where clause stating outlives condition. (RFC 2093)
#![feature(untagged_unions)]
// Type T needs to outlive lifetime 'a. This is not reported due to
// a compilation error in Bar.
union Foo<'a, T> {
field1: Bar<'a, T>
}
// Type U needs to outlive lifetime 'b
union Bar<'b, U> {
field2: &'b U //~ ERROR 25:5: 25:18: the parameter type `U` may not live long enough [E0309]
}
// Type K needs to outlive lifetime 'c.
union Ying<'c, K> {
field1: &'c Yang<K> //~ ERROR 31:5: 31:24: the parameter type `K` may not live long enough [E0309]
}
union Yang<V> {
field2: V
}
fn main() {}

View file

@ -1,31 +0,0 @@
error[E0309]: the parameter type `U` may not live long enough
--> $DIR/union.rs:25:5
|
LL | union Bar<'b, U> {
| - help: consider adding an explicit lifetime bound `U: 'b`...
LL | field2: &'b U //~ ERROR 25:5: 25:18: the parameter type `U` may not live long enough [E0309]
| ^^^^^^^^^^^^^
|
note: ...so that the reference type `&'b U` does not outlive the data it points at
--> $DIR/union.rs:25:5
|
LL | field2: &'b U //~ ERROR 25:5: 25:18: the parameter type `U` may not live long enough [E0309]
| ^^^^^^^^^^^^^
error[E0309]: the parameter type `K` may not live long enough
--> $DIR/union.rs:31:5
|
LL | union Ying<'c, K> {
| - help: consider adding an explicit lifetime bound `K: 'c`...
LL | field1: &'c Yang<K> //~ ERROR 31:5: 31:24: the parameter type `K` may not live long enough [E0309]
| ^^^^^^^^^^^^^^^^^^^
|
note: ...so that the reference type `&'c Yang<K>` does not outlive the data it points at
--> $DIR/union.rs:31:5
|
LL | field1: &'c Yang<K> //~ ERROR 31:5: 31:24: the parameter type `K` may not live long enough [E0309]
| ^^^^^^^^^^^^^^^^^^^
error: aborting due to 2 previous errors
For more information about this error, try `rustc --explain E0309`.