about summary refs log tree commit diff
diff options
context:
space:
mode:
authortoidiu <toidiu@protonmail.com>2018-04-18 22:26:21 -0400
committertoidiu <apoorv@toidiu.com>2018-05-25 09:58:00 -0400
commit3da712381d0d264e31dcfaf9b29bbe8d4a8d1474 (patch)
tree3168a9993ed19ecd3a73336f642c4ff4c97c6f69
parentb86d909f8635f82710c1bf74647c957051cbb23a (diff)
downloadrust-3da712381d0d264e31dcfaf9b29bbe8d4a8d1474.tar.gz
rust-3da712381d0d264e31dcfaf9b29bbe8d4a8d1474.zip
Implement outlives requirements inference for dyn and projections.
Add tests, documentation and attr for feature.
-rw-r--r--src/doc/unstable-book/src/language-features/infer-outlives-requirements.md67
-rw-r--r--src/librustc_typeck/outlives/explicit.rs56
-rw-r--r--src/librustc_typeck/outlives/implicit_empty.rs52
-rw-r--r--src/librustc_typeck/outlives/implicit_infer.rs308
-rw-r--r--src/librustc_typeck/outlives/mod.rs46
-rw-r--r--src/librustc_typeck/outlives/utils.rs167
-rw-r--r--src/libsyntax/feature_gate.rs6
-rw-r--r--src/test/compile-fail/outlives-associated-types.rs25
-rw-r--r--src/test/ui/rfc-2093-infer-outlives/explicit-dyn.rs (renamed from src/test/ui/rfc-2093-infer-outlives/multiple-regions.rs)15
-rw-r--r--src/test/ui/rfc-2093-infer-outlives/explicit-dyn.stderr13
-rw-r--r--src/test/ui/rfc-2093-infer-outlives/explicit-enum.rs (renamed from src/test/ui/rfc-2093-infer-outlives/projections-pass.rs)14
-rw-r--r--src/test/ui/rfc-2093-infer-outlives/explicit-enum.stderr12
-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-projection.rs24
-rw-r--r--src/test/ui/rfc-2093-infer-outlives/explicit-projection.stderr13
-rw-r--r--src/test/ui/rfc-2093-infer-outlives/explicit-struct.rs (renamed from src/test/ui/rfc-2093-infer-outlives/explicit-where-pass.rs)14
-rw-r--r--src/test/ui/rfc-2093-infer-outlives/explicit-struct.stderr12
-rw-r--r--src/test/ui/rfc-2093-infer-outlives/explicit-union.rs (renamed from src/test/ui/rfc-2093-infer-outlives/nested-structs-pass.rs)19
-rw-r--r--src/test/ui/rfc-2093-infer-outlives/explicit-union.stderr12
-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.stderr20
-rw-r--r--src/test/ui/rfc-2093-infer-outlives/nested-enum.rs (renamed from src/test/ui/rfc-2093-infer-outlives/enum-pass.rs)21
-rw-r--r--src/test/ui/rfc-2093-infer-outlives/nested-enum.stderr13
-rw-r--r--src/test/ui/rfc-2093-infer-outlives/nested-regions.rs (renamed from src/test/ui/rfc-2093-infer-outlives/multiple-regions-pass.rs)9
-rw-r--r--src/test/ui/rfc-2093-infer-outlives/nested-regions.stderr14
-rw-r--r--src/test/ui/rfc-2093-infer-outlives/nested-structs.rs15
-rw-r--r--src/test/ui/rfc-2093-infer-outlives/nested-structs.stderr19
-rw-r--r--src/test/ui/rfc-2093-infer-outlives/nested-union.rs (renamed from src/test/ui/rfc-2093-infer-outlives/union-pass.rs)20
-rw-r--r--src/test/ui/rfc-2093-infer-outlives/nested-union.stderr12
-rw-r--r--src/test/ui/rfc-2093-infer-outlives/projection.rs (renamed from src/test/ui/rfc-2093-infer-outlives/reference-pass.rs)11
-rw-r--r--src/test/ui/rfc-2093-infer-outlives/projection.stderr12
-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.rs13
-rw-r--r--src/test/ui/rfc-2093-infer-outlives/reference.stderr19
-rw-r--r--src/test/ui/rfc-2093-infer-outlives/self-dyn.rs25
-rw-r--r--src/test/ui/rfc-2093-infer-outlives/self-dyn.stderr13
-rw-r--r--src/test/ui/rfc-2093-infer-outlives/self-structs.rs24
-rw-r--r--src/test/ui/rfc-2093-infer-outlives/self-structs.stderr12
-rw-r--r--src/test/ui/rfc-2093-infer-outlives/union.rs40
-rw-r--r--src/test/ui/rfc-2093-infer-outlives/union.stderr31
45 files changed, 676 insertions, 725 deletions
diff --git a/src/doc/unstable-book/src/language-features/infer-outlives-requirements.md b/src/doc/unstable-book/src/language-features/infer-outlives-requirements.md
new file mode 100644
index 00000000000..73c7eafdb98
--- /dev/null
+++ b/src/doc/unstable-book/src/language-features/infer-outlives-requirements.md
@@ -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
+```
diff --git a/src/librustc_typeck/outlives/explicit.rs b/src/librustc_typeck/outlives/explicit.rs
index 9a8fd46b0ef..bbe47ecee79 100644
--- a/src/librustc_typeck/outlives/explicit.rs
+++ b/src/librustc_typeck/outlives/explicit.rs
@@ -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;
+
+        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)
+                }
 
-        let filtered_predicates = local_explicit_predicate
-            .predicates
-            .into_iter()
-            .filter(|pred| match pred {
-                ty::Predicate::TypeOutlives(..) | ty::Predicate::RegionOutlives(..) => true,
+                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) {}
 }
diff --git a/src/librustc_typeck/outlives/implicit_empty.rs b/src/librustc_typeck/outlives/implicit_empty.rs
deleted file mode 100644
index b2259c63683..00000000000
--- a/src/librustc_typeck/outlives/implicit_empty.rs
+++ /dev/null
@@ -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) {}
-}
diff --git a/src/librustc_typeck/outlives/implicit_infer.rs b/src/librustc_typeck/outlives/implicit_infer.rs
index e711598c944..c966db98c8e 100644
--- a/src/librustc_typeck/outlives/implicit_infer.rs
+++ b/src/librustc_typeck/outlives/implicit_infer.rs
@@ -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>>>>,
-) {
-    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,
-                    );
-                }
-
-                // `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>,
+    explicit_map: &FxHashMap<DefId, RequiredPredicates<'tcx>>,
+    ignore_self_ty: bool,
 ) {
-    // 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.
+    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);
+
+            // 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);
         }
     }
 }
diff --git a/src/librustc_typeck/outlives/mod.rs b/src/librustc_typeck/outlives/mod.rs
index e5af4c60691..b5ba59d64cd 100644
--- a/src/librustc_typeck/outlives/mod.rs
+++ b/src/librustc_typeck/outlives/mod.rs
@@ -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(
diff --git a/src/librustc_typeck/outlives/utils.rs b/src/librustc_typeck/outlives/utils.rs
new file mode 100644
index 00000000000..5cb1822b04e
--- /dev/null
+++ b/src/librustc_typeck/outlives/utils.rs
@@ -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);
+        }
+    }
+}
diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs
index 3a02646d0af..4293fe9125d 100644
--- a/src/libsyntax/feature_gate.rs
+++ b/src/libsyntax/feature_gate.rs
@@ -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 \
diff --git a/src/test/compile-fail/outlives-associated-types.rs b/src/test/compile-fail/outlives-associated-types.rs
deleted file mode 100644
index 5c392223f88..00000000000
--- a/src/test/compile-fail/outlives-associated-types.rs
+++ /dev/null
@@ -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() { }
diff --git a/src/test/ui/rfc-2093-infer-outlives/multiple-regions.rs b/src/test/ui/rfc-2093-infer-outlives/explicit-dyn.rs
index 7ea1ce2d3dc..445c246a120 100644
--- a/src/test/ui/rfc-2093-infer-outlives/multiple-regions.rs
+++ b/src/test/ui/rfc-2093-infer-outlives/explicit-dyn.rs
@@ -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 {
 }
 
-fn main() {}
+#[rustc_outlives]
+struct Foo<'a, A> //~ ERROR 19:1: 22:2: rustc_outlives
+{
+    foo: Box<dyn Trait<'a, A>>
+}
 
+fn main() {}
diff --git a/src/test/ui/rfc-2093-infer-outlives/explicit-dyn.stderr b/src/test/ui/rfc-2093-infer-outlives/explicit-dyn.stderr
new file mode 100644
index 00000000000..4bb5d90e964
--- /dev/null
+++ b/src/test/ui/rfc-2093-infer-outlives/explicit-dyn.stderr
@@ -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
+
diff --git a/src/test/ui/rfc-2093-infer-outlives/projections-pass.rs b/src/test/ui/rfc-2093-infer-outlives/explicit-enum.rs
index 9c6e84cdd6e..e85b49bb0bf 100644
--- a/src/test/ui/rfc-2093-infer-outlives/projections-pass.rs
+++ b/src/test/ui/rfc-2093-infer-outlives/explicit-enum.rs
@@ -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() {}
 
diff --git a/src/test/ui/rfc-2093-infer-outlives/explicit-enum.stderr b/src/test/ui/rfc-2093-infer-outlives/explicit-enum.stderr
new file mode 100644
index 00000000000..d7438758d77
--- /dev/null
+++ b/src/test/ui/rfc-2093-infer-outlives/explicit-enum.stderr
@@ -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
+
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
deleted file mode 100644
index 45449fa0cf8..00000000000
--- a/src/test/ui/rfc-2093-infer-outlives/explicit-impl-lifetime-pass.rs
+++ /dev/null
@@ -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() {}
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
deleted file mode 100644
index bfd6db1eb5d..00000000000
--- a/src/test/ui/rfc-2093-infer-outlives/explicit-impl-pass.rs
+++ /dev/null
@@ -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() {}
diff --git a/src/test/ui/rfc-2093-infer-outlives/explicit-impl.rs b/src/test/ui/rfc-2093-infer-outlives/explicit-impl.rs
deleted file mode 100644
index 3a10087551c..00000000000
--- a/src/test/ui/rfc-2093-infer-outlives/explicit-impl.rs
+++ /dev/null
@@ -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() { }
diff --git a/src/test/ui/rfc-2093-infer-outlives/explicit-impl.stderr b/src/test/ui/rfc-2093-infer-outlives/explicit-impl.stderr
deleted file mode 100644
index 498d66ef9a5..00000000000
--- a/src/test/ui/rfc-2093-infer-outlives/explicit-impl.stderr
+++ /dev/null
@@ -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`.
diff --git a/src/test/ui/rfc-2093-infer-outlives/explicit-projection.rs b/src/test/ui/rfc-2093-infer-outlives/explicit-projection.rs
new file mode 100644
index 00000000000..2662043c36d
--- /dev/null
+++ b/src/test/ui/rfc-2093-infer-outlives/explicit-projection.rs
@@ -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() {}
diff --git a/src/test/ui/rfc-2093-infer-outlives/explicit-projection.stderr b/src/test/ui/rfc-2093-infer-outlives/explicit-projection.stderr
new file mode 100644
index 00000000000..43ab02d01ed
--- /dev/null
+++ b/src/test/ui/rfc-2093-infer-outlives/explicit-projection.stderr
@@ -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
+
diff --git a/src/test/ui/rfc-2093-infer-outlives/explicit-where-pass.rs b/src/test/ui/rfc-2093-infer-outlives/explicit-struct.rs
index fd5fc79a2ab..d42c9160e1e 100644
--- a/src/test/ui/rfc-2093-infer-outlives/explicit-where-pass.rs
+++ b/src/test/ui/rfc-2093-infer-outlives/explicit-struct.rs
@@ -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() {}
 
diff --git a/src/test/ui/rfc-2093-infer-outlives/explicit-struct.stderr b/src/test/ui/rfc-2093-infer-outlives/explicit-struct.stderr
new file mode 100644
index 00000000000..0223f707e8d
--- /dev/null
+++ b/src/test/ui/rfc-2093-infer-outlives/explicit-struct.stderr
@@ -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
+
diff --git a/src/test/ui/rfc-2093-infer-outlives/nested-structs-pass.rs b/src/test/ui/rfc-2093-infer-outlives/explicit-union.rs
index 9432804cc42..e548b247193 100644
--- a/src/test/ui/rfc-2093-infer-outlives/nested-structs-pass.rs
+++ b/src/test/ui/rfc-2093-infer-outlives/explicit-union.rs
@@ -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() {}
diff --git a/src/test/ui/rfc-2093-infer-outlives/explicit-union.stderr b/src/test/ui/rfc-2093-infer-outlives/explicit-union.stderr
new file mode 100644
index 00000000000..8622ae12aa1
--- /dev/null
+++ b/src/test/ui/rfc-2093-infer-outlives/explicit-union.stderr
@@ -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
+
diff --git a/src/test/ui/rfc-2093-infer-outlives/explicit-where.rs b/src/test/ui/rfc-2093-infer-outlives/explicit-where.rs
deleted file mode 100644
index 81734bf514e..00000000000
--- a/src/test/ui/rfc-2093-infer-outlives/explicit-where.rs
+++ /dev/null
@@ -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() { }
diff --git a/src/test/ui/rfc-2093-infer-outlives/explicit-where.stderr b/src/test/ui/rfc-2093-infer-outlives/explicit-where.stderr
deleted file mode 100644
index 436754c7dc1..00000000000
--- a/src/test/ui/rfc-2093-infer-outlives/explicit-where.stderr
+++ /dev/null
@@ -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`.
diff --git a/src/test/ui/rfc-2093-infer-outlives/multiple-regions.stderr b/src/test/ui/rfc-2093-infer-outlives/multiple-regions.stderr
deleted file mode 100644
index 3722abd5ad6..00000000000
--- a/src/test/ui/rfc-2093-infer-outlives/multiple-regions.stderr
+++ /dev/null
@@ -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`.
diff --git a/src/test/ui/rfc-2093-infer-outlives/enum-pass.rs b/src/test/ui/rfc-2093-infer-outlives/nested-enum.rs
index 2a28bde78a8..85f381ea515 100644
--- a/src/test/ui/rfc-2093-infer-outlives/enum-pass.rs
+++ b/src/test/ui/rfc-2093-infer-outlives/nested-enum.rs
@@ -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() {}
-
diff --git a/src/test/ui/rfc-2093-infer-outlives/nested-enum.stderr b/src/test/ui/rfc-2093-infer-outlives/nested-enum.stderr
new file mode 100644
index 00000000000..54a886a92fd
--- /dev/null
+++ b/src/test/ui/rfc-2093-infer-outlives/nested-enum.stderr
@@ -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
+
diff --git a/src/test/ui/rfc-2093-infer-outlives/multiple-regions-pass.rs b/src/test/ui/rfc-2093-infer-outlives/nested-regions.rs
index 290dbd330a2..792d2a02962 100644
--- a/src/test/ui/rfc-2093-infer-outlives/multiple-regions-pass.rs
+++ b/src/test/ui/rfc-2093-infer-outlives/nested-regions.rs
@@ -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() {}
-
diff --git a/src/test/ui/rfc-2093-infer-outlives/nested-regions.stderr b/src/test/ui/rfc-2093-infer-outlives/nested-regions.stderr
new file mode 100644
index 00000000000..04fe4814a04
--- /dev/null
+++ b/src/test/ui/rfc-2093-infer-outlives/nested-regions.stderr
@@ -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
+
diff --git a/src/test/ui/rfc-2093-infer-outlives/nested-structs.rs b/src/test/ui/rfc-2093-infer-outlives/nested-structs.rs
index 7c444dbd3b0..71a36dfb344 100644
--- a/src/test/ui/rfc-2093-infer-outlives/nested-structs.rs
+++ b/src/test/ui/rfc-2093-infer-outlives/nested-structs.rs
@@ -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() {}
-
diff --git a/src/test/ui/rfc-2093-infer-outlives/nested-structs.stderr b/src/test/ui/rfc-2093-infer-outlives/nested-structs.stderr
index 94d6cbdb5fe..abea71f2d12 100644
--- a/src/test/ui/rfc-2093-infer-outlives/nested-structs.stderr
+++ b/src/test/ui/rfc-2093-infer-outlives/nested-structs.stderr
@@ -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`.
diff --git a/src/test/ui/rfc-2093-infer-outlives/union-pass.rs b/src/test/ui/rfc-2093-infer-outlives/nested-union.rs
index 5e46c2b7f5c..0720e581e2c 100644
--- a/src/test/ui/rfc-2093-infer-outlives/union-pass.rs
+++ b/src/test/ui/rfc-2093-infer-outlives/nested-union.rs
@@ -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() {}
-
diff --git a/src/test/ui/rfc-2093-infer-outlives/nested-union.stderr b/src/test/ui/rfc-2093-infer-outlives/nested-union.stderr
new file mode 100644
index 00000000000..b7b50c15061
--- /dev/null
+++ b/src/test/ui/rfc-2093-infer-outlives/nested-union.stderr
@@ -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
+
diff --git a/src/test/ui/rfc-2093-infer-outlives/reference-pass.rs b/src/test/ui/rfc-2093-infer-outlives/projection.rs
index 903b8a9ddbf..3abce873b28 100644
--- a/src/test/ui/rfc-2093-infer-outlives/reference-pass.rs
+++ b/src/test/ui/rfc-2093-infer-outlives/projection.rs
@@ -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() {}
 
diff --git a/src/test/ui/rfc-2093-infer-outlives/projection.stderr b/src/test/ui/rfc-2093-infer-outlives/projection.stderr
new file mode 100644
index 00000000000..dfaf7793a51
--- /dev/null
+++ b/src/test/ui/rfc-2093-infer-outlives/projection.stderr
@@ -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
+
diff --git a/src/test/ui/rfc-2093-infer-outlives/projections.rs b/src/test/ui/rfc-2093-infer-outlives/projections.rs
deleted file mode 100644
index f6a557c174c..00000000000
--- a/src/test/ui/rfc-2093-infer-outlives/projections.rs
+++ /dev/null
@@ -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() { }
diff --git a/src/test/ui/rfc-2093-infer-outlives/projections.stderr b/src/test/ui/rfc-2093-infer-outlives/projections.stderr
deleted file mode 100644
index 9969cf48ecd..00000000000
--- a/src/test/ui/rfc-2093-infer-outlives/projections.stderr
+++ /dev/null
@@ -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`.
diff --git a/src/test/ui/rfc-2093-infer-outlives/reference.rs b/src/test/ui/rfc-2093-infer-outlives/reference.rs
index 01ccc50a130..56b1bc3c7d1 100644
--- a/src/test/ui/rfc-2093-infer-outlives/reference.rs
+++ b/src/test/ui/rfc-2093-infer-outlives/reference.rs
@@ -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() {}
diff --git a/src/test/ui/rfc-2093-infer-outlives/reference.stderr b/src/test/ui/rfc-2093-infer-outlives/reference.stderr
index 7236bd535c9..785d76e8f22 100644
--- a/src/test/ui/rfc-2093-infer-outlives/reference.stderr
+++ b/src/test/ui/rfc-2093-infer-outlives/reference.stderr
@@ -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`.
diff --git a/src/test/ui/rfc-2093-infer-outlives/self-dyn.rs b/src/test/ui/rfc-2093-infer-outlives/self-dyn.rs
new file mode 100644
index 00000000000..a19bcf8afff
--- /dev/null
+++ b/src/test/ui/rfc-2093-infer-outlives/self-dyn.rs
@@ -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() {}
diff --git a/src/test/ui/rfc-2093-infer-outlives/self-dyn.stderr b/src/test/ui/rfc-2093-infer-outlives/self-dyn.stderr
new file mode 100644
index 00000000000..546ba9db644
--- /dev/null
+++ b/src/test/ui/rfc-2093-infer-outlives/self-dyn.stderr
@@ -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
+
diff --git a/src/test/ui/rfc-2093-infer-outlives/self-structs.rs b/src/test/ui/rfc-2093-infer-outlives/self-structs.rs
new file mode 100644
index 00000000000..c4f8f83bdce
--- /dev/null
+++ b/src/test/ui/rfc-2093-infer-outlives/self-structs.rs
@@ -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() {}
diff --git a/src/test/ui/rfc-2093-infer-outlives/self-structs.stderr b/src/test/ui/rfc-2093-infer-outlives/self-structs.stderr
new file mode 100644
index 00000000000..04284577a07
--- /dev/null
+++ b/src/test/ui/rfc-2093-infer-outlives/self-structs.stderr
@@ -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
+
diff --git a/src/test/ui/rfc-2093-infer-outlives/union.rs b/src/test/ui/rfc-2093-infer-outlives/union.rs
deleted file mode 100644
index 36b1dccb13e..00000000000
--- a/src/test/ui/rfc-2093-infer-outlives/union.rs
+++ /dev/null
@@ -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() {}
-
diff --git a/src/test/ui/rfc-2093-infer-outlives/union.stderr b/src/test/ui/rfc-2093-infer-outlives/union.stderr
deleted file mode 100644
index cd13c423293..00000000000
--- a/src/test/ui/rfc-2093-infer-outlives/union.stderr
+++ /dev/null
@@ -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`.