summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.gitignore1
-rw-r--r--src/librustc/dep_graph/dep_node.rs1
-rw-r--r--src/librustc/ich/impls_ty.rs14
-rw-r--r--src/librustc/ty/maps/config.rs6
-rw-r--r--src/librustc/ty/maps/mod.rs7
-rw-r--r--src/librustc/ty/maps/plumbing.rs1
-rw-r--r--src/librustc/ty/mod.rs16
-rw-r--r--src/librustc_typeck/collect.rs9
-rw-r--r--src/librustc_typeck/diagnostics.rs2
-rw-r--r--src/librustc_typeck/lib.rs1
-rw-r--r--src/librustc_typeck/outlives/explicit.rs82
-rw-r--r--src/librustc_typeck/outlives/implicit_empty.rs52
-rw-r--r--src/librustc_typeck/outlives/implicit_infer.rs442
-rw-r--r--src/librustc_typeck/outlives/mod.rs96
-rw-r--r--src/librustc_typeck/outlives/test.rs22
-rw-r--r--src/libsyntax/feature_gate.rs9
-rw-r--r--src/test/compile-fail/outlives-associated-types.rs4
-rw-r--r--src/test/ui/feature-gate-infer_outlives_requirements.rs18
-rw-r--r--src/test/ui/feature-gate-infer_outlives_requirements.stderr17
-rw-r--r--src/test/ui/rfc-2093-infer-outlives/enum-pass.rs38
-rw-r--r--src/test/ui/rfc-2093-infer-outlives/enum.rs37
-rw-r--r--src/test/ui/rfc-2093-infer-outlives/enum.stderr31
-rw-r--r--src/test/ui/rfc-2093-infer-outlives/explicit-impl-lifetime-pass.rs30
-rw-r--r--src/test/ui/rfc-2093-infer-outlives/explicit-impl-pass.rs30
-rw-r--r--src/test/ui/rfc-2093-infer-outlives/explicit-impl.rs30
-rw-r--r--src/test/ui/rfc-2093-infer-outlives/explicit-impl.stderr17
-rw-r--r--src/test/ui/rfc-2093-infer-outlives/explicit-where-pass.rs27
-rw-r--r--src/test/ui/rfc-2093-infer-outlives/explicit-where.rs23
-rw-r--r--src/test/ui/rfc-2093-infer-outlives/explicit-where.stderr17
-rw-r--r--src/test/ui/rfc-2093-infer-outlives/multiple-regions-pass.rs22
-rw-r--r--src/test/ui/rfc-2093-infer-outlives/multiple-regions.rs19
-rw-r--r--src/test/ui/rfc-2093-infer-outlives/multiple-regions.stderr20
-rw-r--r--src/test/ui/rfc-2093-infer-outlives/nested-structs-pass.rs25
-rw-r--r--src/test/ui/rfc-2093-infer-outlives/nested-structs.rs26
-rw-r--r--src/test/ui/rfc-2093-infer-outlives/nested-structs.stderr17
-rw-r--r--src/test/ui/rfc-2093-infer-outlives/projections-pass.rs23
-rw-r--r--src/test/ui/rfc-2093-infer-outlives/projections.rs20
-rw-r--r--src/test/ui/rfc-2093-infer-outlives/projections.stderr16
-rw-r--r--src/test/ui/rfc-2093-infer-outlives/reference-pass.rs23
-rw-r--r--src/test/ui/rfc-2093-infer-outlives/reference.rs18
-rw-r--r--src/test/ui/rfc-2093-infer-outlives/reference.stderr17
-rw-r--r--src/test/ui/rfc-2093-infer-outlives/union-pass.rs39
-rw-r--r--src/test/ui/rfc-2093-infer-outlives/union.rs40
-rw-r--r--src/test/ui/rfc-2093-infer-outlives/union.stderr31
44 files changed, 1415 insertions, 21 deletions
diff --git a/.gitignore b/.gitignore
index 57407a2399a..efbbf22ffe5 100644
--- a/.gitignore
+++ b/.gitignore
@@ -83,6 +83,7 @@ __pycache__/
/src/libstd_unicode/UnicodeData.txt
/stage[0-9]+/
/target
+target/
/test/
/tmp/
TAGS
diff --git a/src/librustc/dep_graph/dep_node.rs b/src/librustc/dep_graph/dep_node.rs
index 7c5318a96f5..f3f31e5740f 100644
--- a/src/librustc/dep_graph/dep_node.rs
+++ b/src/librustc/dep_graph/dep_node.rs
@@ -500,6 +500,7 @@ define_dep_nodes!( <'tcx>
[] GenericsOfItem(DefId),
[] PredicatesOfItem(DefId),
[] InferredOutlivesOf(DefId),
+ [] InferredOutlivesCrate(CrateNum),
[] SuperPredicatesOfItem(DefId),
[] TraitDefOfItem(DefId),
[] AdtDefOfItem(DefId),
diff --git a/src/librustc/ich/impls_ty.rs b/src/librustc/ich/impls_ty.rs
index af4d3429bb1..41cfac2674b 100644
--- a/src/librustc/ich/impls_ty.rs
+++ b/src/librustc/ich/impls_ty.rs
@@ -1100,6 +1100,20 @@ impl<'a> HashStable<StableHashingContext<'a>> for ty::CrateVariancesMap {
}
}
+impl<'a, 'gcx> HashStable<StableHashingContext<'a>> for ty::CratePredicatesMap<'gcx> {
+ fn hash_stable<W: StableHasherResult>(&self,
+ hcx: &mut StableHashingContext<'a>,
+ hasher: &mut StableHasher<W>) {
+ let ty::CratePredicatesMap {
+ ref predicates,
+ // This is just an irrelevant helper value.
+ empty_predicate: _,
+ } = *self;
+
+ predicates.hash_stable(hcx, hasher);
+ }
+}
+
impl_stable_hash_for!(struct ty::AssociatedItem {
def_id,
name,
diff --git a/src/librustc/ty/maps/config.rs b/src/librustc/ty/maps/config.rs
index 16866636cd9..a4571c161c4 100644
--- a/src/librustc/ty/maps/config.rs
+++ b/src/librustc/ty/maps/config.rs
@@ -155,6 +155,12 @@ impl<'tcx> QueryDescription<'tcx> for queries::crate_variances<'tcx> {
}
}
+impl<'tcx> QueryDescription<'tcx> for queries::inferred_outlives_crate<'tcx> {
+ fn describe(_tcx: TyCtxt, _: CrateNum) -> String {
+ format!("computing the inferred outlives predicates for items in this crate")
+ }
+}
+
impl<'tcx> QueryDescription<'tcx> for queries::mir_shims<'tcx> {
fn describe(tcx: TyCtxt, def: ty::InstanceDef<'tcx>) -> String {
format!("generating MIR shim for `{}`",
diff --git a/src/librustc/ty/maps/mod.rs b/src/librustc/ty/maps/mod.rs
index 5a23a3b952a..6dd43554a98 100644
--- a/src/librustc/ty/maps/mod.rs
+++ b/src/librustc/ty/maps/mod.rs
@@ -102,6 +102,7 @@ define_maps! { <'tcx>
/// associated generics and predicates.
[] fn generics_of: GenericsOfItem(DefId) -> &'tcx ty::Generics,
[] fn predicates_of: PredicatesOfItem(DefId) -> ty::GenericPredicates<'tcx>,
+ [] fn explicit_predicates_of: PredicatesOfItem(DefId) -> ty::GenericPredicates<'tcx>,
/// Maps from the def-id of a trait to the list of
/// super-predicates. This is a subset of the full list of
@@ -139,7 +140,11 @@ define_maps! { <'tcx>
[] fn variances_of: ItemVariances(DefId) -> Lrc<Vec<ty::Variance>>,
/// Maps from def-id of a type to its (inferred) outlives.
- [] fn inferred_outlives_of: InferredOutlivesOf(DefId) -> Vec<ty::Predicate<'tcx>>,
+ [] fn inferred_outlives_of: InferredOutlivesOf(DefId) -> Lrc<Vec<ty::Predicate<'tcx>>>,
+
+ /// Maps from def-id of a type to its (inferred) outlives.
+ [] fn inferred_outlives_crate: InferredOutlivesCrate(CrateNum)
+ -> Lrc<ty::CratePredicatesMap<'tcx>>,
/// Maps from an impl/trait def-id to a list of the def-ids of its items
[] fn associated_item_def_ids: AssociatedItemDefIds(DefId) -> Lrc<Vec<DefId>>,
diff --git a/src/librustc/ty/maps/plumbing.rs b/src/librustc/ty/maps/plumbing.rs
index c04e580a33d..2a1d87421aa 100644
--- a/src/librustc/ty/maps/plumbing.rs
+++ b/src/librustc/ty/maps/plumbing.rs
@@ -1007,6 +1007,7 @@ pub fn force_from_dep_node<'a, 'gcx, 'lcx>(tcx: TyCtxt<'a, 'gcx, 'lcx>,
DepKind::GenericsOfItem => { force!(generics_of, def_id!()); }
DepKind::PredicatesOfItem => { force!(predicates_of, def_id!()); }
DepKind::InferredOutlivesOf => { force!(inferred_outlives_of, def_id!()); }
+ DepKind::InferredOutlivesCrate => { force!(inferred_outlives_crate, LOCAL_CRATE); }
DepKind::SuperPredicatesOfItem => { force!(super_predicates_of, def_id!()); }
DepKind::TraitDefOfItem => { force!(trait_def, def_id!()); }
DepKind::AdtDefOfItem => { force!(adt_def, def_id!()); }
diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs
index 33b59eda7ce..fccba1e6aa7 100644
--- a/src/librustc/ty/mod.rs
+++ b/src/librustc/ty/mod.rs
@@ -956,6 +956,22 @@ pub enum Predicate<'tcx> {
ConstEvaluatable(DefId, &'tcx Substs<'tcx>),
}
+/// The crate outlives map is computed during typeck and contains the
+/// outlives of every item in the local crate. You should not use it
+/// directly, because to do so will make your pass dependent on the
+/// HIR of every item in the local crate. Instead, use
+/// `tcx.inferred_outlives_of()` to get the outlives for a *particular*
+/// item.
+pub struct CratePredicatesMap<'tcx> {
+ /// For each struct with outlive bounds, maps to a vector of the
+ /// predicate of its outlive bounds. If an item has no outlives
+ /// bounds, it will have no entry.
+ pub predicates: FxHashMap<DefId, Lrc<Vec<ty::Predicate<'tcx>>>>,
+
+ /// An empty vector, useful for cloning.
+ pub empty_predicate: Lrc<Vec<ty::Predicate<'tcx>>>,
+}
+
impl<'tcx> AsRef<Predicate<'tcx>> for Predicate<'tcx> {
fn as_ref(&self) -> &Predicate<'tcx> {
self
diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs
index a4f820d1fdc..e2e6a2d7aac 100644
--- a/src/librustc_typeck/collect.rs
+++ b/src/librustc_typeck/collect.rs
@@ -64,6 +64,7 @@ pub fn provide(providers: &mut Providers) {
type_of,
generics_of,
predicates_of,
+ explicit_predicates_of,
super_predicates_of,
type_param_predicates,
trait_def,
@@ -1296,13 +1297,17 @@ fn predicates_of<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
def_id: DefId)
-> ty::GenericPredicates<'tcx> {
let explicit = explicit_predicates_of(tcx, def_id);
+ let predicates = if tcx.sess.features_untracked().infer_outlives_requirements {
+ [&explicit.predicates[..], &tcx.inferred_outlives_of(def_id)[..]].concat()
+ } else { explicit.predicates };
+
ty::GenericPredicates {
parent: explicit.parent,
- predicates: [&explicit.predicates[..], &tcx.inferred_outlives_of(def_id)[..]].concat()
+ predicates: predicates,
}
}
-fn explicit_predicates_of<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
+pub fn explicit_predicates_of<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
def_id: DefId)
-> ty::GenericPredicates<'tcx> {
use rustc::hir::map::*;
diff --git a/src/librustc_typeck/diagnostics.rs b/src/librustc_typeck/diagnostics.rs
index 5a53c008f6c..063d83780d8 100644
--- a/src/librustc_typeck/diagnostics.rs
+++ b/src/librustc_typeck/diagnostics.rs
@@ -4840,11 +4840,11 @@ register_diagnostics! {
E0588, // packed type cannot transitively contain a `[repr(align)]` type
E0592, // duplicate definitions with name `{}`
// E0613, // Removed (merged with E0609)
- E0640, // infer outlives
E0627, // yield statement outside of generator literal
E0632, // cannot provide explicit type parameters when `impl Trait` is used in
// argument position.
E0634, // type has conflicting packed representaton hints
+ E0640, // infer outlives requirements
E0641, // cannot cast to/from a pointer with an unknown kind
E0645, // trait aliases not finished
E0907, // type inside generator must be known in this context
diff --git a/src/librustc_typeck/lib.rs b/src/librustc_typeck/lib.rs
index 3a48e1806af..1f5aa45e79a 100644
--- a/src/librustc_typeck/lib.rs
+++ b/src/librustc_typeck/lib.rs
@@ -82,6 +82,7 @@ This API is completely unstable and subject to change.
#![feature(slice_patterns)]
#![feature(slice_sort_by_cached_key)]
#![feature(dyn_trait)]
+#![feature(underscore_lifetimes)]
#[macro_use] extern crate log;
#[macro_use] extern crate syntax;
diff --git a/src/librustc_typeck/outlives/explicit.rs b/src/librustc_typeck/outlives/explicit.rs
new file mode 100644
index 00000000000..9a8fd46b0ef
--- /dev/null
+++ b/src/librustc_typeck/outlives/explicit.rs
@@ -0,0 +1,82 @@
+// 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::{CrateNum, DefId, LocalDefId, 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;
+
+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();
+
+ // iterate over the entire crate
+ tcx.hir.krate().visit_all_item_likes(&mut ExplicitVisitor {
+ tcx: tcx,
+ explicit_predicates: &mut predicates,
+ crate_num: crate_num,
+ });
+
+ predicates
+}
+
+pub struct ExplicitVisitor<'cx, 'tcx: 'cx> {
+ tcx: TyCtxt<'cx, 'tcx, 'tcx>,
+ explicit_predicates: &'cx mut FxHashMap<DefId, Lrc<Vec<ty::Predicate<'tcx>>>>,
+ crate_num: CrateNum,
+}
+
+impl<'cx, 'tcx> ItemLikeVisitor<'tcx> for ExplicitVisitor<'cx, 'tcx> {
+ fn visit_item(&mut self, item: &'tcx hir::Item) {
+ let def_id = DefId {
+ krate: self.crate_num,
+ index: item.hir_id.owner,
+ };
+
+ let local_explicit_predicate = self.tcx.explicit_predicates_of(def_id);
+
+ let filtered_predicates = local_explicit_predicate
+ .predicates
+ .into_iter()
+ .filter(|pred| match pred {
+ ty::Predicate::TypeOutlives(..) | ty::Predicate::RegionOutlives(..) => true,
+
+ ty::Predicate::Trait(..)
+ | ty::Predicate::Projection(..)
+ | ty::Predicate::WellFormed(..)
+ | 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);
+ }
+ _ => {}
+ }
+
+ self.explicit_predicates
+ .insert(def_id, Lrc::new(filtered_predicates));
+ }
+
+ fn visit_trait_item(&mut self, trait_item: &'tcx hir::TraitItem) {}
+
+ fn visit_impl_item(&mut self, impl_item: &'tcx hir::ImplItem) {}
+}
diff --git a/src/librustc_typeck/outlives/implicit_empty.rs b/src/librustc_typeck/outlives/implicit_empty.rs
new file mode 100644
index 00000000000..b2259c63683
--- /dev/null
+++ b/src/librustc_typeck/outlives/implicit_empty.rs
@@ -0,0 +1,52 @@
+// 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) {}
+}
diff --git a/src/librustc_typeck/outlives/implicit_infer.rs b/src/librustc_typeck/outlives/implicit_infer.rs
new file mode 100644
index 00000000000..ac53a6d4a3f
--- /dev/null
+++ b/src/librustc_typeck/outlives/implicit_infer.rs
@@ -0,0 +1,442 @@
+// 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.
+
+#![allow(unused)]
+
+use rustc::hir;
+use rustc::hir::def::{CtorKind, Def};
+use rustc::hir::def_id::{self, CrateNum, DefId, LOCAL_CRATE};
+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 syntax::{abi, ast};
+use syntax_pos::{Span, DUMMY_SP};
+
+/// Infer predicates for the items in the crate.
+///
+/// global_inferred_outlives: this is initially the empty map that
+/// was generated by walking the items in the crate. This will
+/// now be filled with inferred predicates.
+pub fn infer_predicates<'tcx>(
+ tcx: TyCtxt<'_, 'tcx, 'tcx>,
+ explicit_map: &FxHashMap<DefId, Lrc<Vec<ty::Predicate<'tcx>>>>,
+) -> FxHashMap<DefId, RequiredPredicates<'tcx>> {
+ debug!("infer_predicates");
+
+ let mut predicates_added = true;
+
+ let mut global_inferred_outlives = FxHashMap::default();
+
+ // If new predicates were added then we need to re-calculate
+ // all crates since there could be new implied predicates.
+ while predicates_added {
+ predicates_added = false;
+
+ let mut visitor = InferVisitor {
+ tcx: tcx,
+ global_inferred_outlives: &mut global_inferred_outlives,
+ predicates_added: &mut predicates_added,
+ explicit_map: explicit_map,
+ };
+
+ // Visit all the crates and infer predicates
+ tcx.hir.krate().visit_all_item_likes(&mut visitor);
+ }
+
+ global_inferred_outlives
+}
+
+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>>>>,
+}
+
+/// 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
+ .hir
+ .as_local_node_id(item_did)
+ .expect("expected local def-id");
+ let item = match self.tcx.hir.get(node_id) {
+ hir::map::NodeItem(item) => item,
+ _ => bug!(),
+ };
+
+ let mut item_required_predicates = RequiredPredicates::default();
+ match item.node {
+ hir::ItemUnion(..) | hir::ItemEnum(..) | hir::ItemStruct(..) => {
+ let adt_def = self.tcx.adt_def(item_did);
+
+ // Iterate over all fields in item_did
+ for field_def in adt_def.all_fields() {
+ // Calculating the predicate requirements necessary
+ // for item_did.
+ //
+ // For field of type &'a T (reference) or TyAdt
+ // (struct/enum/union) there will be outlive
+ // requirements for adt_def.
+ let field_ty = self.tcx.type_of(field_def.did);
+ insert_required_predicates_to_be_wf(
+ self.tcx,
+ field_ty,
+ self.global_inferred_outlives,
+ &mut item_required_predicates,
+ self.explicit_map,
+ );
+ }
+ }
+
+ _ => {}
+ };
+
+ // If new predicates were added (`local_predicate_map` has more
+ // predicates than the `global_inferred_outlives`), the new predicates
+ // might result in implied predicates for their parent types.
+ // 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
+ .get(&item_did)
+ .map(|p| p.len())
+ .unwrap_or(0);
+ if item_required_predicates.len() > item_predicates_len {
+ *self.predicates_added = true;
+ self.global_inferred_outlives
+ .insert(item_did, item_required_predicates);
+ }
+ }
+
+ fn visit_trait_item(&mut self, trait_item: &'tcx hir::TraitItem) {}
+
+ fn visit_impl_item(&mut self, impl_item: &'tcx hir::ImplItem) {}
+}
+
+fn insert_required_predicates_to_be_wf<'tcx>(
+ tcx: TyCtxt<'_, 'tcx, '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>>>>,
+) {
+ for ty in field_ty.walk() {
+ match ty.sty {
+ // The field is of type &'a T which means that we will have
+ // a predicate requirement of T: 'a (T outlives 'a).
+ //
+ // We also want to calculate potential predicates for the T
+ ty::TyRef(region, mt) => {
+ insert_outlives_predicate(tcx, mt.ty.into(), region, required_predicates);
+ }
+
+ // For each TyAdt (struct/enum/union) type `Foo<'a, T>`, we
+ // 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
+ //
+ // Example 1:
+ //
+ // struct Foo<'a, T> {
+ // field1: Bar<'a, T>
+ // }
+ //
+ // struct Bar<'b, U> {
+ // field2: &'b U
+ // }
+ //
+ // Here, when processing the type of `field1`, we would
+ // request the set of implicit predicates computed for `Bar`
+ // thus far. This will initially come back empty, but in next
+ // 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`.
+ if let Some(unsubstituted_predicates) = global_inferred_outlives.get(&def.did) {
+ for unsubstituted_predicate in unsubstituted_predicates {
+ // `unsubstituted_predicate` is `U: 'b` in the
+ // example above. So apply the substitution to
+ // get `T: 'a` (or `predicate`):
+ let predicate = unsubstituted_predicate.subst(tcx, substs);
+ insert_outlives_predicate(
+ tcx,
+ predicate.0,
+ predicate.1,
+ required_predicates,
+ );
+ }
+ }
+
+ // 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);
+ }
+
+ 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() {
+ check_explicit_predicates(
+ tcx,
+ &p.skip_binder().def_id,
+ &[region.into()],
+ required_predicates,
+ explicit_map,
+ );
+ }
+ }
+
+ ty::TyProjection(obj) => {
+ // FIXME This corresponds to `<T as Foo<'a>>::Bar`. In this case, we should use the
+ // explicit predicates as well.
+ check_explicit_predicates(
+ tcx,
+ &obj.item_def_id,
+ obj.substs,
+ required_predicates,
+ explicit_map,
+ );
+ }
+
+ _ => {}
+ }
+ }
+}
+
+/// We also have to check the explicit predicates
+/// declared on the type.
+///
+/// struct Foo<'a, T> {
+/// field1: Bar<T>
+/// }
+///
+/// struct Bar<U> where U: 'static, U: Foo {
+/// ...
+/// }
+///
+/// Here, we should fetch the explicit predicates, which
+/// 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>(
+ tcx: TyCtxt<'_, 'tcx, 'tcx>,
+ def_id: &DefId,
+ substs: &[Kind<'tcx>],
+ required_predicates: &mut RequiredPredicates<'tcx>,
+ explicit_map: &FxHashMap<DefId, Lrc<Vec<ty::Predicate<'tcx>>>>,
+) {
+ 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.0.subst(tcx, substs);
+ insert_outlives_predicate(
+ tcx,
+ predicate.0.into(),
+ predicate.1,
+ required_predicates,
+ );
+ }
+
+ // `poly` is `PolyRegionOutlivesPredicate<OutlivesPredicate<Ty>>`
+ // where OutlivesPredicate<region1, region2> is the predicate
+ // we want to add.
+ ty::Predicate::RegionOutlives(poly) => {
+ let predicate = poly.0.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.
+ //
+ // 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_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"),
+ }
+ }
+ }
+
+ 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);
+ }
+ }
+}
diff --git a/src/librustc_typeck/outlives/mod.rs b/src/librustc_typeck/outlives/mod.rs
index 1127028cbc8..bad0c68a6fe 100644
--- a/src/librustc_typeck/outlives/mod.rs
+++ b/src/librustc_typeck/outlives/mod.rs
@@ -7,23 +7,105 @@
// <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::hir::def_id::DefId;
-use rustc::ty::{self, TyCtxt};
+#![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;
pub fn provide(providers: &mut Providers) {
*providers = Providers {
inferred_outlives_of,
+ inferred_outlives_crate,
..*providers
};
}
-//todo
-fn inferred_outlives_of<'a, 'tcx>(_tcx: TyCtxt<'a, 'tcx, 'tcx>, _def_id: DefId)
- -> Vec<ty::Predicate<'tcx>> {
- Vec::new()
+fn inferred_outlives_of<'a, 'tcx>(
+ tcx: TyCtxt<'a, 'tcx, 'tcx>,
+ item_def_id: DefId,
+) -> Lrc<Vec<ty::Predicate<'tcx>>> {
+ let id = tcx.hir
+ .as_local_node_id(item_def_id)
+ .expect("expected local def-id");
+
+ match tcx.hir.get(id) {
+ 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
+ .predicates
+ .get(&item_def_id)
+ .unwrap_or(&crate_map.empty_predicate)
+ .clone()
+ }
+
+ _ => Lrc::new(Vec::new()),
+ },
+
+ _ => Lrc::new(Vec::new()),
+ }
+}
+
+fn inferred_outlives_crate<'tcx>(
+ tcx: TyCtxt<'_, 'tcx, 'tcx>,
+ crate_num: CrateNum,
+) -> Lrc<CratePredicatesMap<'tcx>> {
+ // Compute a map from each struct/enum/union S to the **explicit**
+ // outlives predicates (`T: 'a`, `'a: 'b`) that the user wrote.
+ // Typically there won't be many of these, except in older code where
+ // they were mandatory. Nonetheless, we have to ensure that every such
+ // predicate is satisfied, so they form a kind of base set of requirements
+ // for the type.
+
+ // Compute the inferred predicates
+ let exp = explicit::explicit_predicates(tcx, crate_num);
+ let mut 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
+ .iter()
+ .map(|(&def_id, set)| {
+ let vec: Vec<ty::Predicate<'tcx>> = set.iter()
+ .map(
+ |ty::OutlivesPredicate(kind1, region2)| match kind1.unpack() {
+ UnpackedKind::Type(ty1) => ty::Predicate::TypeOutlives(ty::Binder(
+ ty::OutlivesPredicate(ty1, region2),
+ )),
+ UnpackedKind::Lifetime(region1) => ty::Predicate::RegionOutlives(
+ ty::Binder(ty::OutlivesPredicate(region1, region2)),
+ ),
+ },
+ )
+ .collect();
+ (def_id, Lrc::new(vec))
+ })
+ .collect();
+
+ let empty_predicate = Lrc::new(Vec::new());
+
+ Lrc::new(ty::CratePredicatesMap {
+ predicates,
+ empty_predicate,
+ })
}
diff --git a/src/librustc_typeck/outlives/test.rs b/src/librustc_typeck/outlives/test.rs
index 196e6605494..c3c2ae667dd 100644
--- a/src/librustc_typeck/outlives/test.rs
+++ b/src/librustc_typeck/outlives/test.rs
@@ -13,11 +13,13 @@ use rustc::hir::itemlikevisit::ItemLikeVisitor;
use rustc::ty::TyCtxt;
pub fn test_inferred_outlives<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) {
- tcx.hir.krate().visit_all_item_likes(&mut OutlivesTest { tcx });
+ tcx.hir
+ .krate()
+ .visit_all_item_likes(&mut OutlivesTest { tcx });
}
struct OutlivesTest<'a, 'tcx: 'a> {
- tcx: TyCtxt<'a, 'tcx, 'tcx>
+ tcx: TyCtxt<'a, 'tcx, 'tcx>,
}
impl<'a, 'tcx> ItemLikeVisitor<'tcx> for OutlivesTest<'a, 'tcx> {
@@ -28,14 +30,16 @@ impl<'a, 'tcx> ItemLikeVisitor<'tcx> for OutlivesTest<'a, 'tcx> {
// attribute and report an error with various results if found.
if self.tcx.has_attr(item_def_id, "rustc_outlives") {
let inferred_outlives_of = self.tcx.inferred_outlives_of(item_def_id);
- span_err!(self.tcx.sess,
- item.span,
- E0640,
- "{:?}",
- inferred_outlives_of);
+ span_err!(
+ self.tcx.sess,
+ item.span,
+ E0640,
+ "{:?}",
+ inferred_outlives_of
+ );
}
}
- fn visit_trait_item(&mut self, _: &'tcx hir::TraitItem) { }
- fn visit_impl_item(&mut self, _: &'tcx hir::ImplItem) { }
+ fn visit_trait_item(&mut self, _: &'tcx hir::TraitItem) {}
+ fn visit_impl_item(&mut self, _: &'tcx hir::ImplItem) {}
}
diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs
index df39757d1eb..73ebfc20876 100644
--- a/src/libsyntax/feature_gate.rs
+++ b/src/libsyntax/feature_gate.rs
@@ -426,6 +426,9 @@ declare_features! (
// Use `?` as the Kleene "at most one" operator
(active, macro_at_most_once_rep, "1.25.0", Some(48075), None),
+ // Infer outlives requirements; RFC 2093
+ (active, infer_outlives_requirements, "1.26.0", Some(44493), None),
+
// Multiple patterns with `|` in `if let` and `while let`
(active, if_while_or_patterns, "1.26.0", Some(48215), None),
@@ -1023,6 +1026,12 @@ pub const BUILTIN_ATTRIBUTES: &'static [(&'static str, AttributeType, AttributeG
"never will be stable",
cfg_fn!(rustc_attrs))),
+ // RFC #2093
+ ("infer_outlives_requirements", Normal, Gated(Stability::Unstable,
+ "infer_outlives_requirements",
+ "infer outlives requirements is an experimental feature",
+ cfg_fn!(infer_outlives_requirements))),
+
("wasm_custom_section", Whitelisted, Gated(Stability::Unstable,
"wasm_custom_section",
"attribute is currently unstable",
diff --git a/src/test/compile-fail/outlives-associated-types.rs b/src/test/compile-fail/outlives-associated-types.rs
index 778394c9fc8..5c392223f88 100644
--- a/src/test/compile-fail/outlives-associated-types.rs
+++ b/src/test/compile-fail/outlives-associated-types.rs
@@ -8,6 +8,8 @@
// 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)]
@@ -16,7 +18,7 @@
// https://github.com/rust-lang/rfcs/blob/master/text/2093-infer-outlives.md#example-1-a-reference
#[rustc_outlives]
-struct Direct<'a, T> { //~ ERROR 19:1: 21:2: [] [E0640]
+struct Direct<'a, T> { //~ ERROR 21:1: 23:2: [Binder(OutlivesPredicate(T, ReEarlyBound(0, 'a)))] [E0640]
field: &'a T
}
diff --git a/src/test/ui/feature-gate-infer_outlives_requirements.rs b/src/test/ui/feature-gate-infer_outlives_requirements.rs
new file mode 100644
index 00000000000..01ccc50a130
--- /dev/null
+++ b/src/test/ui/feature-gate-infer_outlives_requirements.rs
@@ -0,0 +1,18 @@
+// 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 T needs to outlive lifetime 'a.
+struct Foo<'a, T> {
+ bar: &'a [T] //~ ERROR the parameter type `T` may not live long enough [E0309]
+}
+
+fn main() { }
diff --git a/src/test/ui/feature-gate-infer_outlives_requirements.stderr b/src/test/ui/feature-gate-infer_outlives_requirements.stderr
new file mode 100644
index 00000000000..560e494b582
--- /dev/null
+++ b/src/test/ui/feature-gate-infer_outlives_requirements.stderr
@@ -0,0 +1,17 @@
+error[E0309]: the parameter type `T` may not live long enough
+ --> $DIR/feature-gate-infer_outlives_requirements.rs:15:5
+ |
+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]
+ | ^^^^^^^^^^^^
+ |
+note: ...so that the reference type `&'a [T]` does not outlive the data it points at
+ --> $DIR/feature-gate-infer_outlives_requirements.rs:15:5
+ |
+LL | bar: &'a [T] //~ 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`.
diff --git a/src/test/ui/rfc-2093-infer-outlives/enum-pass.rs b/src/test/ui/rfc-2093-infer-outlives/enum-pass.rs
new file mode 100644
index 00000000000..8c7275bb1a7
--- /dev/null
+++ b/src/test/ui/rfc-2093-infer-outlives/enum-pass.rs
@@ -0,0 +1,38 @@
+// 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.
+
+// must-compile-successfully
+
+#![feature(infer_outlives_requirements)]
+
+// Type T needs to outlive lifetime 'a.
+enum Foo<'a, T> {
+
+ 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() {}
+
diff --git a/src/test/ui/rfc-2093-infer-outlives/enum.rs b/src/test/ui/rfc-2093-infer-outlives/enum.rs
new file mode 100644
index 00000000000..7d0427adb9f
--- /dev/null
+++ b/src/test/ui/rfc-2093-infer-outlives/enum.rs
@@ -0,0 +1,37 @@
+// 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)
+
+// Type T needs to outlive lifetime 'a.
+enum Foo<'a, T> {
+
+ One(Bar<'a, T>)
+}
+
+// Type U needs to outlive lifetime 'b
+struct Bar<'b, U> {
+ field2: &'b U //~ ERROR 23:5: 23:18: the parameter type `U` may not live long enough [E0309]
+}
+
+
+
+// Type K needs to outlive lifetime 'c.
+enum Ying<'c, K> {
+ One(&'c Yang<K>) //~ ERROR 30:9: 30:21: the parameter type `K` may not live long enough [E0309]
+}
+
+struct Yang<V> {
+ field2: V
+}
+
+fn main() {}
diff --git a/src/test/ui/rfc-2093-infer-outlives/enum.stderr b/src/test/ui/rfc-2093-infer-outlives/enum.stderr
new file mode 100644
index 00000000000..e6eaf9b4754
--- /dev/null
+++ b/src/test/ui/rfc-2093-infer-outlives/enum.stderr
@@ -0,0 +1,31 @@
+error[E0309]: the parameter type `U` may not live long enough
+ --> $DIR/enum.rs:23:5
+ |
+LL | struct Bar<'b, U> {
+ | - help: consider adding an explicit lifetime bound `U: 'b`...
+LL | field2: &'b U //~ ERROR 23:5: 23: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/enum.rs:23:5
+ |
+LL | field2: &'b U //~ ERROR 23:5: 23:18: the parameter type `U` may not live long enough [E0309]
+ | ^^^^^^^^^^^^^
+
+error[E0309]: the parameter type `K` may not live long enough
+ --> $DIR/enum.rs:30:9
+ |
+LL | enum Ying<'c, K> {
+ | - help: consider adding an explicit lifetime bound `K: 'c`...
+LL | One(&'c Yang<K>) //~ ERROR 30:9: 30:21: 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/enum.rs:30:9
+ |
+LL | One(&'c Yang<K>) //~ ERROR 30:9: 30:21: 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`.
diff --git a/src/test/ui/rfc-2093-infer-outlives/explicit-impl-lifetime-pass.rs b/src/test/ui/rfc-2093-infer-outlives/explicit-impl-lifetime-pass.rs
new file mode 100644
index 00000000000..da578386adb
--- /dev/null
+++ b/src/test/ui/rfc-2093-infer-outlives/explicit-impl-lifetime-pass.rs
@@ -0,0 +1,30 @@
+// 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
+// must-compile-successfully
+
+#![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() {}
diff --git a/src/test/ui/rfc-2093-infer-outlives/explicit-impl-pass.rs b/src/test/ui/rfc-2093-infer-outlives/explicit-impl-pass.rs
new file mode 100644
index 00000000000..fd74fe30bb6
--- /dev/null
+++ b/src/test/ui/rfc-2093-infer-outlives/explicit-impl-pass.rs
@@ -0,0 +1,30 @@
+// 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
+// must-compile-successfully
+
+#![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() {}
diff --git a/src/test/ui/rfc-2093-infer-outlives/explicit-impl.rs b/src/test/ui/rfc-2093-infer-outlives/explicit-impl.rs
new file mode 100644
index 00000000000..3a10087551c
--- /dev/null
+++ b/src/test/ui/rfc-2093-infer-outlives/explicit-impl.rs
@@ -0,0 +1,30 @@
+// 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() { }
diff --git a/src/test/ui/rfc-2093-infer-outlives/explicit-impl.stderr b/src/test/ui/rfc-2093-infer-outlives/explicit-impl.stderr
new file mode 100644
index 00000000000..498d66ef9a5
--- /dev/null
+++ b/src/test/ui/rfc-2093-infer-outlives/explicit-impl.stderr
@@ -0,0 +1,17 @@
+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`.
diff --git a/src/test/ui/rfc-2093-infer-outlives/explicit-where-pass.rs b/src/test/ui/rfc-2093-infer-outlives/explicit-where-pass.rs
new file mode 100644
index 00000000000..e51b5a16b45
--- /dev/null
+++ b/src/test/ui/rfc-2093-infer-outlives/explicit-where-pass.rs
@@ -0,0 +1,27 @@
+// 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.
+
+// must-compile-successfully
+
+#![feature(infer_outlives_requirements)]
+// Outlives requirementes are inferred (RFC 2093)
+
+// explicit-where: infer U: 'b
+struct ExFoo<'b, U> {
+ bar: ExBar<'b, U>
+}
+struct ExBar<'a, T> where T: 'a {
+ x: &'a (),
+ y: T,
+}
+
+
+fn main() {}
+
diff --git a/src/test/ui/rfc-2093-infer-outlives/explicit-where.rs b/src/test/ui/rfc-2093-infer-outlives/explicit-where.rs
new file mode 100644
index 00000000000..81734bf514e
--- /dev/null
+++ b/src/test/ui/rfc-2093-infer-outlives/explicit-where.rs
@@ -0,0 +1,23 @@
+// 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() { }
diff --git a/src/test/ui/rfc-2093-infer-outlives/explicit-where.stderr b/src/test/ui/rfc-2093-infer-outlives/explicit-where.stderr
new file mode 100644
index 00000000000..436754c7dc1
--- /dev/null
+++ b/src/test/ui/rfc-2093-infer-outlives/explicit-where.stderr
@@ -0,0 +1,17 @@
+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`.
diff --git a/src/test/ui/rfc-2093-infer-outlives/multiple-regions-pass.rs b/src/test/ui/rfc-2093-infer-outlives/multiple-regions-pass.rs
new file mode 100644
index 00000000000..be686a80048
--- /dev/null
+++ b/src/test/ui/rfc-2093-infer-outlives/multiple-regions-pass.rs
@@ -0,0 +1,22 @@
+// 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.
+
+// must-compile-successfully
+
+#![feature(infer_outlives_requirements)]
+// Outlives requirementes are inferred (RFC 2093)
+
+// multiple-regions: infer 'b: 'a
+struct MultiFoo<'a, 'b, T> {
+ x: &'a &'b T
+}
+
+fn main() {}
+
diff --git a/src/test/ui/rfc-2093-infer-outlives/multiple-regions.rs b/src/test/ui/rfc-2093-infer-outlives/multiple-regions.rs
new file mode 100644
index 00000000000..7ea1ce2d3dc
--- /dev/null
+++ b/src/test/ui/rfc-2093-infer-outlives/multiple-regions.rs
@@ -0,0 +1,19 @@
+// 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.
+
+// Needs an explicit where clause stating outlives condition. (RFC 2093)
+
+// 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]
+}
+
+fn main() {}
+
diff --git a/src/test/ui/rfc-2093-infer-outlives/multiple-regions.stderr b/src/test/ui/rfc-2093-infer-outlives/multiple-regions.stderr
new file mode 100644
index 00000000000..3722abd5ad6
--- /dev/null
+++ b/src/test/ui/rfc-2093-infer-outlives/multiple-regions.stderr
@@ -0,0 +1,20 @@
+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`.
diff --git a/src/test/ui/rfc-2093-infer-outlives/nested-structs-pass.rs b/src/test/ui/rfc-2093-infer-outlives/nested-structs-pass.rs
new file mode 100644
index 00000000000..02581457fcc
--- /dev/null
+++ b/src/test/ui/rfc-2093-infer-outlives/nested-structs-pass.rs
@@ -0,0 +1,25 @@
+// 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.
+
+// must-compile-successfully
+
+#![feature(infer_outlives_requirements)]
+// Outlives requirementes are inferred (RFC 2093)
+
+// nested-structs: infer U: 'b and therefore T: 'a
+struct NestFoo<'a, T> {
+ field1: NestBar<'a, T>
+}
+struct NestBar<'b, U> {
+ field2: &'b U
+}
+
+fn main() {}
+
diff --git a/src/test/ui/rfc-2093-infer-outlives/nested-structs.rs b/src/test/ui/rfc-2093-infer-outlives/nested-structs.rs
new file mode 100644
index 00000000000..7c444dbd3b0
--- /dev/null
+++ b/src/test/ui/rfc-2093-infer-outlives/nested-structs.rs
@@ -0,0 +1,26 @@
+// 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.
+
+// Needs an explicit where clause stating outlives condition. (RFC 2093)
+
+
+// Type T needs to outlive lifetime 'a. This is not reported due to
+// a compilation error in Bar.
+struct Foo<'a, T> {
+ 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]
+}
+
+fn main() {}
+
diff --git a/src/test/ui/rfc-2093-infer-outlives/nested-structs.stderr b/src/test/ui/rfc-2093-infer-outlives/nested-structs.stderr
new file mode 100644
index 00000000000..94d6cbdb5fe
--- /dev/null
+++ b/src/test/ui/rfc-2093-infer-outlives/nested-structs.stderr
@@ -0,0 +1,17 @@
+error[E0309]: the parameter type `U` may not live long enough
+ --> $DIR/nested-structs.rs:22:5
+ |
+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]
+ | ^^^^^^^^^^^^^
+ |
+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]
+ | ^^^^^^^^^^^^^
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0309`.
diff --git a/src/test/ui/rfc-2093-infer-outlives/projections-pass.rs b/src/test/ui/rfc-2093-infer-outlives/projections-pass.rs
new file mode 100644
index 00000000000..1234e27b866
--- /dev/null
+++ b/src/test/ui/rfc-2093-infer-outlives/projections-pass.rs
@@ -0,0 +1,23 @@
+// 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.
+
+// must-compile-successfully
+
+#![feature(infer_outlives_requirements)]
+// Outlives requirementes are inferred (RFC 2093)
+
+// projections: infer <Iterator>::Item: 'a
+struct ProjFoo<'a, T: Iterator> {
+ bar: &'a T::Item
+}
+
+
+fn main() {}
+
diff --git a/src/test/ui/rfc-2093-infer-outlives/projections.rs b/src/test/ui/rfc-2093-infer-outlives/projections.rs
new file mode 100644
index 00000000000..f6a557c174c
--- /dev/null
+++ b/src/test/ui/rfc-2093-infer-outlives/projections.rs
@@ -0,0 +1,20 @@
+// 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() { }
diff --git a/src/test/ui/rfc-2093-infer-outlives/projections.stderr b/src/test/ui/rfc-2093-infer-outlives/projections.stderr
new file mode 100644
index 00000000000..9969cf48ecd
--- /dev/null
+++ b/src/test/ui/rfc-2093-infer-outlives/projections.stderr
@@ -0,0 +1,16 @@
+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`.
diff --git a/src/test/ui/rfc-2093-infer-outlives/reference-pass.rs b/src/test/ui/rfc-2093-infer-outlives/reference-pass.rs
new file mode 100644
index 00000000000..f357685e139
--- /dev/null
+++ b/src/test/ui/rfc-2093-infer-outlives/reference-pass.rs
@@ -0,0 +1,23 @@
+// 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.
+
+// must-compile-successfully
+
+#![feature(infer_outlives_requirements)]
+// Outlives requirementes are inferred (RFC 2093)
+
+// reference: infer T: 'a
+struct RefFoo<'a, T> {
+ bar: &'a [T]
+}
+
+
+fn main() {}
+
diff --git a/src/test/ui/rfc-2093-infer-outlives/reference.rs b/src/test/ui/rfc-2093-infer-outlives/reference.rs
new file mode 100644
index 00000000000..01ccc50a130
--- /dev/null
+++ b/src/test/ui/rfc-2093-infer-outlives/reference.rs
@@ -0,0 +1,18 @@
+// 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 T needs to outlive lifetime 'a.
+struct Foo<'a, T> {
+ bar: &'a [T] //~ ERROR the parameter type `T` may not live long enough [E0309]
+}
+
+fn main() { }
diff --git a/src/test/ui/rfc-2093-infer-outlives/reference.stderr b/src/test/ui/rfc-2093-infer-outlives/reference.stderr
new file mode 100644
index 00000000000..7236bd535c9
--- /dev/null
+++ b/src/test/ui/rfc-2093-infer-outlives/reference.stderr
@@ -0,0 +1,17 @@
+error[E0309]: the parameter type `T` may not live long enough
+ --> $DIR/reference.rs:15:5
+ |
+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]
+ | ^^^^^^^^^^^^
+ |
+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]
+ | ^^^^^^^^^^^^
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0309`.
diff --git a/src/test/ui/rfc-2093-infer-outlives/union-pass.rs b/src/test/ui/rfc-2093-infer-outlives/union-pass.rs
new file mode 100644
index 00000000000..b4a61346b01
--- /dev/null
+++ b/src/test/ui/rfc-2093-infer-outlives/union-pass.rs
@@ -0,0 +1,39 @@
+// 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.
+
+// must-compile-successfully
+
+#![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> {
+ field1: Bar<'a, T>
+}
+
+// Type U needs to outlive lifetime 'b
+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() {}
+
diff --git a/src/test/ui/rfc-2093-infer-outlives/union.rs b/src/test/ui/rfc-2093-infer-outlives/union.rs
new file mode 100644
index 00000000000..36b1dccb13e
--- /dev/null
+++ b/src/test/ui/rfc-2093-infer-outlives/union.rs
@@ -0,0 +1,40 @@
+// 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() {}
+
diff --git a/src/test/ui/rfc-2093-infer-outlives/union.stderr b/src/test/ui/rfc-2093-infer-outlives/union.stderr
new file mode 100644
index 00000000000..cd13c423293
--- /dev/null
+++ b/src/test/ui/rfc-2093-infer-outlives/union.stderr
@@ -0,0 +1,31 @@
+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`.