about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--src/librustc_mir/borrow_check/nll/region_infer/mod.rs279
-rw-r--r--src/librustc_mir/borrow_check/nll/universal_regions.rs17
-rw-r--r--src/test/ui/nll/ty-outlives/projection-no-regions-closure.rs68
-rw-r--r--src/test/ui/nll/ty-outlives/projection-no-regions-closure.stderr157
-rw-r--r--src/test/ui/nll/ty-outlives/projection-no-regions-fn.rs (renamed from src/test/ui/nll/ty-outlives/projection-fn.rs)2
-rw-r--r--src/test/ui/nll/ty-outlives/projection-no-regions-fn.stderr (renamed from src/test/ui/nll/ty-outlives/projection-fn.stderr)12
-rw-r--r--src/test/ui/nll/ty-outlives/projection-one-region-closure.rs106
-rw-r--r--src/test/ui/nll/ty-outlives/projection-one-region-closure.stderr194
-rw-r--r--src/test/ui/nll/ty-outlives/projection-one-region-trait-bound-closure.rs106
-rw-r--r--src/test/ui/nll/ty-outlives/projection-one-region-trait-bound-closure.stderr204
-rw-r--r--src/test/ui/nll/ty-outlives/projection-one-region-trait-bound-static-closure.rs99
-rw-r--r--src/test/ui/nll/ty-outlives/projection-one-region-trait-bound-static-closure.stderr155
-rw-r--r--src/test/ui/nll/ty-outlives/projection-two-region-trait-bound-closure.rs135
-rw-r--r--src/test/ui/nll/ty-outlives/projection-two-region-trait-bound-closure.stderr326
14 files changed, 1758 insertions, 102 deletions
diff --git a/src/librustc_mir/borrow_check/nll/region_infer/mod.rs b/src/librustc_mir/borrow_check/nll/region_infer/mod.rs
index 244abb40798..f03e8bd7ac1 100644
--- a/src/librustc_mir/borrow_check/nll/region_infer/mod.rs
+++ b/src/librustc_mir/borrow_check/nll/region_infer/mod.rs
@@ -19,7 +19,7 @@ use rustc::infer::region_constraints::{GenericKind, VarOrigins};
 use rustc::mir::{ClosureOutlivesRequirement, ClosureOutlivesSubject, ClosureRegionRequirements,
                  Location, Mir};
 use rustc::traits::ObligationCause;
-use rustc::ty::{self, RegionVid, TypeFoldable};
+use rustc::ty::{self, RegionVid, Ty, TypeFoldable};
 use rustc_data_structures::indexed_vec::IndexVec;
 use std::fmt;
 use std::rc::Rc;
@@ -478,7 +478,6 @@ impl<'tcx> RegionInferenceContext<'tcx> {
         propagated_outlives_requirements: &mut Vec<ClosureOutlivesRequirement<'gcx>>,
     ) -> bool {
         let tcx = infcx.tcx;
-        let gcx = tcx.global_tcx();
 
         let TypeTest {
             generic_kind,
@@ -488,80 +487,158 @@ impl<'tcx> RegionInferenceContext<'tcx> {
             test: _,
         } = type_test;
 
-        // TODO. For now, just fail to promote anything with a
-        // region. This is obviously too strict: we will for example
-        // fail to promote `<T as Foo<'static>>::Bar` to our
-        // caller. But it is always sound not to promote, that just
-        // means more errors, and ignoring regions is a convenient
-        // starting point. This is because we would want to promote to
-        // a type that references the region-vids of the closure, for
-        // which we have no global representation just now.
         let generic_ty = generic_kind.to_ty(tcx);
-        if generic_ty.has_free_regions() {
-            return false;
-        }
-        let generic_ty = gcx.lift(&generic_ty).unwrap();
+        let subject = match self.try_promote_type_test_subject(infcx, generic_ty) {
+            Some(s) => s,
+            None => return false,
+        };
 
         // Find some bounding subject-region R+ that is a super-region
         // of the existing subject-region R. This should be a non-local, universal
         // region, which ensures it can be encoded in a `ClosureOutlivesRequirement`.
-        let lower_bound_plus = self.promoted_type_test_bound(*lower_bound);
+        let lower_bound_plus = self.non_local_universal_upper_bound(*lower_bound);
         assert!(self.universal_regions.is_universal_region(lower_bound_plus));
         assert!(!self.universal_regions
             .is_local_free_region(lower_bound_plus));
 
         propagated_outlives_requirements.push(ClosureOutlivesRequirement {
-            subject: ClosureOutlivesSubject::Ty(generic_ty),
+            subject,
             outlived_free_region: lower_bound_plus,
             blame_span: *span,
         });
         true
     }
 
-    /// Here, `lower_bound` (henceforth, `'r`) represents the bound from
-    /// some type-test `T: 'r`. We are a closure and have found that
-    /// `T: 'r` is not locally satisfiable, so we want to propagate
-    /// this constraint to our creator. It is sound for us to do so
-    /// with some `'r+` known to our creator, where `'r+: 'r`.
+    /// When we promote a type test `T: 'r`, we have to convert the
+    /// type `T` into something we can store in a query result (so
+    /// something allocated for `'gcx`). This is problematic if `ty`
+    /// contains regions. During the course of NLL region checking, we
+    /// will have replaced all of those regions with fresh inference
+    /// variables. To create a test subject, we want to replace those
+    /// inference variables with some region from the closure
+    /// signature -- this is not always possible, so this is a
+    /// fallible process. Presuming we do find a suitable region, we
+    /// will represent it with a `ReClosureBound`, which is a
+    /// `RegionKind` variant that can be allocated in the gcx.
+    fn try_promote_type_test_subject<'gcx>(
+        &self,
+        infcx: &InferCtxt<'_, 'gcx, 'tcx>,
+        ty: Ty<'tcx>,
+    ) -> Option<ClosureOutlivesSubject<'gcx>> {
+        let tcx = infcx.tcx;
+        let gcx = tcx.global_tcx();
+        let inferred_values = self.inferred_values
+            .as_ref()
+            .expect("region values not yet inferred");
+
+        debug!("try_promote_type_test_subject(ty = {:?})", ty);
+
+        let ty = tcx.fold_regions(&ty, &mut false, |r, _depth| {
+            let region_vid = self.to_region_vid(r);
+
+            // The challenge if this. We have some region variable `r`
+            // whose value is a set of CFG points and universal
+            // regions. We want to find if that set is *equivalent* to
+            // any of the named regions found in the closure.
+            //
+            // To do so, we compute the
+            // `non_local_universal_upper_bound`. This will be a
+            // non-local, universal region that is greater than `r`.
+            // However, it might not be *contained* within `r`, so
+            // then we further check whether this bound is contained
+            // in `r`. If so, we can say that `r` is equivalent to the
+            // bound.
+            //
+            // Let's work through a few examples. For these, imagine
+            // that we have 3 non-local regions (I'll denote them as
+            // `'static`, `'a`, and `'b`, though of course in the code
+            // they would be represented with indices) where:
+            //
+            // - `'static: 'a`
+            // - `'static: 'b`
+            //
+            // First, let's assume that `r` is some existential
+            // variable with an inferred value `{'a, 'static}` (plus
+            // some CFG nodes). In this case, the non-local upper
+            // bound is `'static`, since that outlives `'a`. `'static`
+            // is also a member of `r` and hence we consider `r`
+            // equivalent to `'static` (and replace it with
+            // `'static`).
+            //
+            // Now let's consider the inferred value `{'a, 'b}`. This
+            // means `r` is effectively `'a | 'b`. I'm not sure if
+            // this can come about, actually, but assuming it did, we
+            // would get a non-local upper bound of `'static`. Since
+            // `'static` is not contained in `r`, we would fail to
+            // find an equivalent.
+            let upper_bound = self.non_local_universal_upper_bound(region_vid);
+            if inferred_values.contains(region_vid, upper_bound) {
+                tcx.mk_region(ty::ReClosureBound(upper_bound))
+            } else {
+                // In the case of a failure, use a `ReVar`
+                // result. This will cause the `lift` later on to
+                // fail.
+                r
+            }
+        });
+        debug!("try_promote_type_test_subject: folded ty = {:?}", ty);
+
+        // `lift` will only fail if we failed to promote some region.
+        let ty = gcx.lift(&ty)?;
+
+        Some(ClosureOutlivesSubject::Ty(ty))
+    }
+
+    /// Given some universal or existential region `r`, finds a
+    /// non-local, universal region `r+` that outlives `r` at entry to (and
+    /// exit from) the closure. In the worst case, this will be
+    /// `'static`.
     ///
-    /// The tricky bit here: this region `'r` may contain (a) any
-    /// number of points in the CFG and (b) any number of `end('x)`
-    /// elements of universally quantified regions. To communicate with
-    /// our creator, however, we have to pick exactly one universally
-    /// quantified region -- in other words, exactly one `end('x)`
-    /// element -- that they understand and which will be `'r+`.
+    /// This is used for two purposes. First, if we are propagated
+    /// some requirement `T: r`, we can use this method to enlarge `r`
+    /// to something we can encode for our creator (which only knows
+    /// about non-local, universal regions). It is also used when
+    /// encoding `T` as part of `try_promote_type_test_subject` (see
+    /// that fn for details).
     ///
-    /// We do this as follows:
+    /// Since `r` is (potentially) an existential region, it has some
+    /// value which may include (a) any number of points in the CFG
+    /// and (b) any number of `end('x)` elements of universally
+    /// quantified regions. To convert this into a single universal
+    /// region we do as follows:
     ///
     /// - Ignore the CFG points in `'r`. All universally quantified regions
     ///   include the CFG anyhow.
     /// - For each `end('x)` element in `'r`, compute the mutual LUB, yielding
     ///   a result `'y`.
     /// - Finally, we take the non-local upper bound of `'y`.
-    fn promoted_type_test_bound(&self, lower_bound: RegionVid) -> RegionVid {
+    ///   - This uses `UniversalRegions::non_local_upper_bound`, which
+    ///     is similar to this method but only works on universal
+    ///     regions).
+    fn non_local_universal_upper_bound(&self, r: RegionVid) -> RegionVid {
         let inferred_values = self.inferred_values.as_ref().unwrap();
 
         debug!(
-            "promoted_type_test_bound(lower_bound={:?}={})",
-            lower_bound,
-            inferred_values.region_value_str(lower_bound)
+            "non_local_universal_upper_bound(r={:?}={})",
+            r,
+            inferred_values.region_value_str(r)
         );
 
         // Find the smallest universal region that contains all other
         // universal regions within `region`.
         let mut lub = self.universal_regions.fr_fn_body;
-        for ur in inferred_values.universal_regions_outlived_by(lower_bound) {
+        for ur in inferred_values.universal_regions_outlived_by(r) {
             lub = self.universal_regions.postdom_upper_bound(lub, ur);
         }
 
-        debug!("promoted_type_test_bound: lub={:?}", lub);
+        debug!("non_local_universal_upper_bound: lub={:?}", lub);
 
         // Grow further to get smallest universal region known to
         // creator.
         let non_local_lub = self.universal_regions.non_local_upper_bound(lub);
 
         debug!(
-            "promoted_type_test_bound: non_local_lub={:?}",
+            "non_local_universal_upper_bound: non_local_lub={:?}",
             non_local_lub
         );
 
@@ -680,32 +757,8 @@ impl<'tcx> RegionInferenceContext<'tcx> {
         // Go through each of the universal regions `fr` and check that
         // they did not grow too large, accumulating any requirements
         // for our caller into the `outlives_requirements` vector.
-        let mut outlives_requirements = vec![];
         for (fr, _) in universal_definitions {
-            self.check_universal_region(infcx, fr, &mut outlives_requirements);
-
-            // Propagate unsatisfied requirements if possible, else
-            // report them.
-            if let Some(propagated_outlives_requirements) = &mut propagated_outlives_requirements {
-                propagated_outlives_requirements.extend(outlives_requirements.drain(..));
-            } else {
-                for outlives_requirement in outlives_requirements.drain(..) {
-                    let fr = match outlives_requirement.subject {
-                        ClosureOutlivesSubject::Region(fr) => fr,
-                        _ => span_bug!(
-                            outlives_requirement.blame_span,
-                            "check_universal_region() produced requirement w/ non-region subject"
-                        ),
-                    };
-
-                    self.report_error(
-                        infcx,
-                        fr,
-                        outlives_requirement.outlived_free_region,
-                        outlives_requirement.blame_span,
-                    );
-                }
-            }
+            self.check_universal_region(infcx, fr, &mut propagated_outlives_requirements);
         }
     }
 
@@ -721,7 +774,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
         &self,
         infcx: &InferCtxt<'_, 'gcx, 'tcx>,
         longer_fr: RegionVid,
-        propagated_outlives_requirements: &mut Vec<ClosureOutlivesRequirement<'gcx>>,
+        propagated_outlives_requirements: &mut Option<&mut Vec<ClosureOutlivesRequirement<'gcx>>>,
     ) {
         let inferred_values = self.inferred_values.as_ref().unwrap();
 
@@ -743,33 +796,39 @@ impl<'tcx> RegionInferenceContext<'tcx> {
 
             let blame_span = self.blame_span(longer_fr, shorter_fr);
 
-            // Shrink `fr` until we find a non-local region (if we do).
-            // We'll call that `fr-` -- it's ever so slightly smaller than `fr`.
-            if let Some(fr_minus) = self.universal_regions.non_local_lower_bound(longer_fr) {
-                debug!("check_universal_region: fr_minus={:?}", fr_minus);
-
-                // Grow `shorter_fr` until we find a non-local
-                // regon. (We always will.)  We'll call that
-                // `shorter_fr+` -- it's ever so slightly larger than
-                // `fr`.
-                let shorter_fr_plus = self.universal_regions.non_local_upper_bound(shorter_fr);
-                debug!(
-                    "check_universal_region: shorter_fr_plus={:?}",
-                    shorter_fr_plus
-                );
+            if let Some(propagated_outlives_requirements) = propagated_outlives_requirements {
+                // Shrink `fr` until we find a non-local region (if we do).
+                // We'll call that `fr-` -- it's ever so slightly smaller than `fr`.
+                if let Some(fr_minus) = self.universal_regions.non_local_lower_bound(longer_fr) {
+                    debug!("check_universal_region: fr_minus={:?}", fr_minus);
+
+                    // Grow `shorter_fr` until we find a non-local
+                    // regon. (We always will.)  We'll call that
+                    // `shorter_fr+` -- it's ever so slightly larger than
+                    // `fr`.
+                    let shorter_fr_plus = self.universal_regions.non_local_upper_bound(shorter_fr);
+                    debug!(
+                        "check_universal_region: shorter_fr_plus={:?}",
+                        shorter_fr_plus
+                    );
 
-                // Push the constraint `fr-: shorter_fr+`
-                propagated_outlives_requirements.push(ClosureOutlivesRequirement {
-                    subject: ClosureOutlivesSubject::Region(fr_minus),
-                    outlived_free_region: shorter_fr_plus,
-                    blame_span: blame_span,
-                });
-                return;
+                    // Push the constraint `fr-: shorter_fr+`
+                    propagated_outlives_requirements.push(ClosureOutlivesRequirement {
+                        subject: ClosureOutlivesSubject::Region(fr_minus),
+                        outlived_free_region: shorter_fr_plus,
+                        blame_span: blame_span,
+                    });
+                    return;
+                }
             }
 
-            // If we could not shrink `fr` to something smaller that
-            // the external users care about, then we can't pass the
-            // buck; just report an error.
+            // If we are not in a context where we can propagate
+            // errors, or we could not shrink `fr` to something
+            // smaller, then just report an error.
+            //
+            // Note: in this case, we use the unapproximated regions
+            // to report the error. This gives better error messages
+            // in some cases.
             self.report_error(infcx, longer_fr, shorter_fr, blame_span);
         }
     }
@@ -878,8 +937,8 @@ impl fmt::Debug for Constraint {
     }
 }
 
-pub trait ClosureRegionRequirementsExt<'gcx> {
-    fn apply_requirements<'tcx>(
+pub trait ClosureRegionRequirementsExt<'gcx, 'tcx> {
+    fn apply_requirements(
         &self,
         infcx: &InferCtxt<'_, 'gcx, 'tcx>,
         body_id: ast::NodeId,
@@ -887,9 +946,18 @@ pub trait ClosureRegionRequirementsExt<'gcx> {
         closure_def_id: DefId,
         closure_substs: ty::ClosureSubsts<'tcx>,
     );
+
+    fn subst_closure_mapping<T>(
+        &self,
+        infcx: &InferCtxt<'_, 'gcx, 'tcx>,
+        closure_mapping: &IndexVec<RegionVid, ty::Region<'tcx>>,
+        value: &T,
+    ) -> T
+    where
+        T: TypeFoldable<'tcx>;
 }
 
-impl<'gcx> ClosureRegionRequirementsExt<'gcx> for ClosureRegionRequirements<'gcx> {
+impl<'gcx, 'tcx> ClosureRegionRequirementsExt<'gcx, 'tcx> for ClosureRegionRequirements<'gcx> {
     /// Given an instance T of the closure type, this method
     /// instantiates the "extra" requirements that we computed for the
     /// closure into the inference context. This has the effect of
@@ -902,7 +970,7 @@ impl<'gcx> ClosureRegionRequirementsExt<'gcx> for ClosureRegionRequirements<'gcx
     /// a vector. Then we can just index into that vector to extract
     /// out the corresponding region from T and apply the
     /// requirements.
-    fn apply_requirements<'tcx>(
+    fn apply_requirements(
         &self,
         infcx: &InferCtxt<'_, 'gcx, 'tcx>,
         body_id: ast::NodeId,
@@ -927,7 +995,7 @@ impl<'gcx> ClosureRegionRequirementsExt<'gcx> for ClosureRegionRequirements<'gcx
         // into a vector.  These are the regions that we will be
         // relating to one another.
         let closure_mapping =
-            UniversalRegions::closure_mapping(infcx, user_closure_ty, self.num_external_vids);
+            &UniversalRegions::closure_mapping(infcx, user_closure_ty, self.num_external_vids);
         debug!("apply_requirements: closure_mapping={:?}", closure_mapping);
 
         // Create the predicates.
@@ -943,15 +1011,24 @@ impl<'gcx> ClosureRegionRequirementsExt<'gcx> for ClosureRegionRequirements<'gcx
                     debug!(
                         "apply_requirements: region={:?} \
                          outlived_region={:?} \
-                         outlives_requirements={:?}",
+                         outlives_requirement={:?}",
                         region,
                         outlived_region,
-                        outlives_requirement
+                        outlives_requirement,
                     );
                     infcx.sub_regions(origin, outlived_region, region);
                 }
 
                 ClosureOutlivesSubject::Ty(ty) => {
+                    let ty = self.subst_closure_mapping(infcx, closure_mapping, &ty);
+                    debug!(
+                        "apply_requirements: ty={:?} \
+                         outlived_region={:?} \
+                         outlives_requirement={:?}",
+                        ty,
+                        outlived_region,
+                        outlives_requirement,
+                    );
                     infcx.register_region_obligation(
                         body_id,
                         RegionObligation {
@@ -964,4 +1041,22 @@ impl<'gcx> ClosureRegionRequirementsExt<'gcx> for ClosureRegionRequirements<'gcx
             }
         }
     }
+
+    fn subst_closure_mapping<T>(
+        &self,
+        infcx: &InferCtxt<'_, 'gcx, 'tcx>,
+        closure_mapping: &IndexVec<RegionVid, ty::Region<'tcx>>,
+        value: &T,
+    ) -> T
+    where
+        T: TypeFoldable<'tcx>
+    {
+        infcx.tcx.fold_regions(value, &mut false, |r, _depth| {
+            if let ty::ReClosureBound(vid) = r {
+                closure_mapping[*vid]
+            } else {
+                bug!("subst_closure_mapping: encountered non-closure bound free region {:?}", r)
+            }
+        })
+    }
 }
diff --git a/src/librustc_mir/borrow_check/nll/universal_regions.rs b/src/librustc_mir/borrow_check/nll/universal_regions.rs
index d3e75626e63..5f4a72542b2 100644
--- a/src/librustc_mir/borrow_check/nll/universal_regions.rs
+++ b/src/librustc_mir/borrow_check/nll/universal_regions.rs
@@ -247,17 +247,24 @@ impl<'tcx> UniversalRegions<'tcx> {
         (FIRST_GLOBAL_INDEX..self.num_universals).map(RegionVid::new)
     }
 
-    /// True if `r` is classied as a global region.
+    /// True if `r` is classified as a global region.
     pub fn is_global_free_region(&self, r: RegionVid) -> bool {
         self.region_classification(r) == Some(RegionClassification::Global)
     }
 
-    /// True if `r` is classied as an external region.
+    /// True if `r` is classified as an external region.
     pub fn is_extern_free_region(&self, r: RegionVid) -> bool {
         self.region_classification(r) == Some(RegionClassification::External)
     }
 
-    /// True if `r` is classied as an local region.
+    /// True if `r` is a free region that is classified as global or
+    /// extern.  This is an important category, because these regions
+    /// can be referenced in `ClosureRegionRequirements`.
+    pub fn is_non_local_free_region(&self, r: RegionVid) -> bool {
+        self.region_classification(r) == Some(RegionClassification::Local)
+    }
+
+    /// True if `r` is classified as an local region.
     pub fn is_local_free_region(&self, r: RegionVid) -> bool {
         self.region_classification(r) == Some(RegionClassification::Local)
     }
@@ -324,6 +331,10 @@ impl<'tcx> UniversalRegions<'tcx> {
         relation: &TransitiveRelation<RegionVid>,
         fr0: RegionVid,
     ) -> Option<RegionVid> {
+        // This method assumes that `fr0` is one of the universally
+        // quantified region variables.
+        assert!(self.is_universal_region(fr0));
+
         let mut external_parents = vec![];
         let mut queue = vec![&fr0];
 
diff --git a/src/test/ui/nll/ty-outlives/projection-no-regions-closure.rs b/src/test/ui/nll/ty-outlives/projection-no-regions-closure.rs
new file mode 100644
index 00000000000..b91c01fb671
--- /dev/null
+++ b/src/test/ui/nll/ty-outlives/projection-no-regions-closure.rs
@@ -0,0 +1,68 @@
+// Copyright 2016 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.
+
+// compile-flags:-Znll -Zborrowck=mir -Zverbose
+
+// Tests closures that propagate an outlives relationship to their
+// creator where the subject is a projection with no regions (`<T as
+// Iterator>::Item`, to be exact).
+
+#![allow(warnings)]
+#![feature(dyn_trait)]
+#![feature(rustc_attrs)]
+
+trait Anything { }
+
+impl<T> Anything for T { }
+
+fn with_signature<'a, T, F>(x: Box<T>, op: F) -> Box<dyn Anything + 'a>
+    where F: FnOnce(Box<T>) -> Box<dyn Anything + 'a>
+{
+    op(x)
+}
+
+#[rustc_regions]
+fn no_region<'a, T>(x: Box<T>) -> Box<dyn Anything + 'a>
+where
+    T: Iterator,
+{
+    with_signature(x, |mut y| Box::new(y.next()))
+    //~^ WARNING not reporting region error due to -Znll
+    //~| ERROR failed type test
+}
+
+#[rustc_regions]
+fn correct_region<'a, T>(x: Box<T>) -> Box<dyn Anything + 'a>
+where
+    T: 'a + Iterator,
+{
+    with_signature(x, |mut y| Box::new(y.next()))
+}
+
+#[rustc_regions]
+fn wrong_region<'a, 'b, T>(x: Box<T>) -> Box<dyn Anything + 'a>
+where
+    T: 'b + Iterator,
+{
+    with_signature(x, |mut y| Box::new(y.next()))
+    //~^ WARNING not reporting region error due to -Znll
+    //~| ERROR failed type test
+}
+
+#[rustc_regions]
+fn outlives_region<'a, 'b, T>(x: Box<T>) -> Box<dyn Anything + 'a>
+where
+    T: 'b + Iterator,
+    'b: 'a,
+{
+    with_signature(x, |mut y| Box::new(y.next()))
+}
+
+fn main() {}
diff --git a/src/test/ui/nll/ty-outlives/projection-no-regions-closure.stderr b/src/test/ui/nll/ty-outlives/projection-no-regions-closure.stderr
new file mode 100644
index 00000000000..1d124f2d49a
--- /dev/null
+++ b/src/test/ui/nll/ty-outlives/projection-no-regions-closure.stderr
@@ -0,0 +1,157 @@
+warning: not reporting region error due to -Znll
+  --> $DIR/projection-no-regions-closure.rs:36:31
+   |
+36 |     with_signature(x, |mut y| Box::new(y.next()))
+   |                               ^^^^^^^^^^^^^^^^^^
+
+warning: not reporting region error due to -Znll
+  --> $DIR/projection-no-regions-closure.rs:54:31
+   |
+54 |     with_signature(x, |mut y| Box::new(y.next()))
+   |                               ^^^^^^^^^^^^^^^^^^
+
+note: External requirements
+  --> $DIR/projection-no-regions-closure.rs:36:23
+   |
+36 |     with_signature(x, |mut y| Box::new(y.next()))
+   |                       ^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: defining type: DefId(0/1:15 ~ projection_no_regions_closure[317d]::no_region[0]::{{closure}}[0]) with closure substs [
+               '_#1r,
+               T,
+               i32,
+               extern "rust-call" fn((std::boxed::Box<T>,)) -> std::boxed::Box<Anything + '_#2r>
+           ]
+   = note: number of external vids: 3
+   = note: where <T as std::iter::Iterator>::Item: '_#2r
+
+note: External requirements
+  --> $DIR/projection-no-regions-closure.rs:46:23
+   |
+46 |     with_signature(x, |mut y| Box::new(y.next()))
+   |                       ^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: defining type: DefId(0/1:18 ~ projection_no_regions_closure[317d]::correct_region[0]::{{closure}}[0]) with closure substs [
+               '_#1r,
+               T,
+               i32,
+               extern "rust-call" fn((std::boxed::Box<T>,)) -> std::boxed::Box<Anything + '_#2r>
+           ]
+   = note: number of external vids: 3
+   = note: where <T as std::iter::Iterator>::Item: '_#2r
+
+note: External requirements
+  --> $DIR/projection-no-regions-closure.rs:54:23
+   |
+54 |     with_signature(x, |mut y| Box::new(y.next()))
+   |                       ^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: defining type: DefId(0/1:22 ~ projection_no_regions_closure[317d]::wrong_region[0]::{{closure}}[0]) with closure substs [
+               '_#1r,
+               '_#2r,
+               T,
+               i32,
+               extern "rust-call" fn((std::boxed::Box<T>,)) -> std::boxed::Box<Anything + '_#3r>
+           ]
+   = note: number of external vids: 4
+   = note: where <T as std::iter::Iterator>::Item: '_#3r
+
+note: External requirements
+  --> $DIR/projection-no-regions-closure.rs:65:23
+   |
+65 |     with_signature(x, |mut y| Box::new(y.next()))
+   |                       ^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: defining type: DefId(0/1:26 ~ projection_no_regions_closure[317d]::outlives_region[0]::{{closure}}[0]) with closure substs [
+               '_#1r,
+               '_#2r,
+               T,
+               i32,
+               extern "rust-call" fn((std::boxed::Box<T>,)) -> std::boxed::Box<Anything + '_#3r>
+           ]
+   = note: number of external vids: 4
+   = note: where <T as std::iter::Iterator>::Item: '_#3r
+
+error: failed type test: TypeTest { generic_kind: ProjectionTy { substs: Slice([T]), item_def_id: DefId(2/0:1697 ~ core[2633]::iter[0]::iterator[0]::Iterator[0]::Item[0]) }, lower_bound: '_#4r, point: bb0[5], span: $DIR/projection-no-regions-closure.rs:36:23: 36:49, test: IsOutlivedByAnyRegionIn(['_#2r]) }
+  --> $DIR/projection-no-regions-closure.rs:36:23
+   |
+36 |     with_signature(x, |mut y| Box::new(y.next()))
+   |                       ^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+note: No external requirements
+  --> $DIR/projection-no-regions-closure.rs:32:1
+   |
+32 | / fn no_region<'a, T>(x: Box<T>) -> Box<dyn Anything + 'a>
+33 | | where
+34 | |     T: Iterator,
+35 | | {
+...  |
+38 | |     //~| ERROR failed type test
+39 | | }
+   | |_^
+   |
+   = note: defining type: DefId(0/0:6 ~ projection_no_regions_closure[317d]::no_region[0]) with substs [
+               '_#1r,
+               T
+           ]
+
+note: No external requirements
+  --> $DIR/projection-no-regions-closure.rs:42:1
+   |
+42 | / fn correct_region<'a, T>(x: Box<T>) -> Box<dyn Anything + 'a>
+43 | | where
+44 | |     T: 'a + Iterator,
+45 | | {
+46 | |     with_signature(x, |mut y| Box::new(y.next()))
+47 | | }
+   | |_^
+   |
+   = note: defining type: DefId(0/0:7 ~ projection_no_regions_closure[317d]::correct_region[0]) with substs [
+               '_#1r,
+               T
+           ]
+
+error: failed type test: TypeTest { generic_kind: ProjectionTy { substs: Slice([T]), item_def_id: DefId(2/0:1697 ~ core[2633]::iter[0]::iterator[0]::Iterator[0]::Item[0]) }, lower_bound: '_#6r, point: bb0[5], span: $DIR/projection-no-regions-closure.rs:54:23: 54:49, test: IsOutlivedByAnyRegionIn(['_#2r, '_#3r]) }
+  --> $DIR/projection-no-regions-closure.rs:54:23
+   |
+54 |     with_signature(x, |mut y| Box::new(y.next()))
+   |                       ^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+note: No external requirements
+  --> $DIR/projection-no-regions-closure.rs:50:1
+   |
+50 | / fn wrong_region<'a, 'b, T>(x: Box<T>) -> Box<dyn Anything + 'a>
+51 | | where
+52 | |     T: 'b + Iterator,
+53 | | {
+...  |
+56 | |     //~| ERROR failed type test
+57 | | }
+   | |_^
+   |
+   = note: defining type: DefId(0/0:8 ~ projection_no_regions_closure[317d]::wrong_region[0]) with substs [
+               '_#1r,
+               '_#2r,
+               T
+           ]
+
+note: No external requirements
+  --> $DIR/projection-no-regions-closure.rs:60:1
+   |
+60 | / fn outlives_region<'a, 'b, T>(x: Box<T>) -> Box<dyn Anything + 'a>
+61 | | where
+62 | |     T: 'b + Iterator,
+63 | |     'b: 'a,
+64 | | {
+65 | |     with_signature(x, |mut y| Box::new(y.next()))
+66 | | }
+   | |_^
+   |
+   = note: defining type: DefId(0/0:9 ~ projection_no_regions_closure[317d]::outlives_region[0]) with substs [
+               '_#1r,
+               '_#2r,
+               T
+           ]
+
+error: aborting due to 2 previous errors
+
diff --git a/src/test/ui/nll/ty-outlives/projection-fn.rs b/src/test/ui/nll/ty-outlives/projection-no-regions-fn.rs
index 677d1352788..b7822eb259b 100644
--- a/src/test/ui/nll/ty-outlives/projection-fn.rs
+++ b/src/test/ui/nll/ty-outlives/projection-no-regions-fn.rs
@@ -8,7 +8,7 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-// compile-flags:-Znll -Zborrowck=mir
+// compile-flags:-Znll -Zborrowck=mir -Zverbose
 
 #![allow(warnings)]
 #![feature(dyn_trait)]
diff --git a/src/test/ui/nll/ty-outlives/projection-fn.stderr b/src/test/ui/nll/ty-outlives/projection-no-regions-fn.stderr
index 77eabef6545..5c3bd04f3b1 100644
--- a/src/test/ui/nll/ty-outlives/projection-fn.stderr
+++ b/src/test/ui/nll/ty-outlives/projection-no-regions-fn.stderr
@@ -1,23 +1,23 @@
 warning: not reporting region error due to -Znll
-  --> $DIR/projection-fn.rs:24:5
+  --> $DIR/projection-no-regions-fn.rs:24:5
    |
 24 |     Box::new(x.next())
    |     ^^^^^^^^^^^^^^^^^^
 
 warning: not reporting region error due to -Znll
-  --> $DIR/projection-fn.rs:40:5
+  --> $DIR/projection-no-regions-fn.rs:40:5
    |
 40 |     Box::new(x.next())
    |     ^^^^^^^^^^^^^^^^^^
 
-error: failed type test: TypeTest { generic_kind: ProjectionTy { substs: Slice([T]), item_def_id: DefId(2/0:1695 ~ core[2633]::iter[0]::iterator[0]::Iterator[0]::Item[0]) }, lower_bound: '_#4r, point: bb5[0], span: $DIR/projection-fn.rs:24:5: 24:23, test: IsOutlivedByAnyRegionIn(['_#2r]) }
-  --> $DIR/projection-fn.rs:24:5
+error: failed type test: TypeTest { generic_kind: ProjectionTy { substs: Slice([T]), item_def_id: DefId(2/0:1697 ~ core[2633]::iter[0]::iterator[0]::Iterator[0]::Item[0]) }, lower_bound: '_#4r, point: bb5[0], span: $DIR/projection-no-regions-fn.rs:24:5: 24:23, test: IsOutlivedByAnyRegionIn(['_#2r]) }
+  --> $DIR/projection-no-regions-fn.rs:24:5
    |
 24 |     Box::new(x.next())
    |     ^^^^^^^^^^^^^^^^^^
 
-error: failed type test: TypeTest { generic_kind: ProjectionTy { substs: Slice([T]), item_def_id: DefId(2/0:1695 ~ core[2633]::iter[0]::iterator[0]::Iterator[0]::Item[0]) }, lower_bound: '_#5r, point: bb5[0], span: $DIR/projection-fn.rs:40:5: 40:23, test: IsOutlivedByAnyRegionIn(['_#2r, '_#3r]) }
-  --> $DIR/projection-fn.rs:40:5
+error: failed type test: TypeTest { generic_kind: ProjectionTy { substs: Slice([T]), item_def_id: DefId(2/0:1697 ~ core[2633]::iter[0]::iterator[0]::Iterator[0]::Item[0]) }, lower_bound: '_#5r, point: bb5[0], span: $DIR/projection-no-regions-fn.rs:40:5: 40:23, test: IsOutlivedByAnyRegionIn(['_#2r, '_#3r]) }
+  --> $DIR/projection-no-regions-fn.rs:40:5
    |
 40 |     Box::new(x.next())
    |     ^^^^^^^^^^^^^^^^^^
diff --git a/src/test/ui/nll/ty-outlives/projection-one-region-closure.rs b/src/test/ui/nll/ty-outlives/projection-one-region-closure.rs
new file mode 100644
index 00000000000..cd9b1c2a8ce
--- /dev/null
+++ b/src/test/ui/nll/ty-outlives/projection-one-region-closure.rs
@@ -0,0 +1,106 @@
+// Copyright 2016 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.
+
+// Test cases where we constrain `<T as Anything<'b>>::AssocType` to
+// outlive `'a` and there are no bounds in the trait definition of
+// `Anything`. This means that the constraint can only be satisfied in two
+// ways:
+//
+// - by ensuring that `T: 'a` and `'b: 'a`, or
+// - by something in the where clauses.
+//
+// As of this writing, the where clause option does not work because
+// of limitations in our region inferencing system (this is true both
+// with and without NLL). See `projection_outlives`.
+//
+// Ensuring that both `T: 'a` and `'b: 'a` holds does work (`elements_outlive`).
+
+// compile-flags:-Znll -Zborrowck=mir -Zverbose
+
+#![allow(warnings)]
+#![feature(dyn_trait)]
+#![feature(rustc_attrs)]
+
+use std::cell::Cell;
+
+trait Anything<'a> {
+    type AssocType;
+}
+
+fn with_signature<'a, T, F>(cell: Cell<&'a ()>, t: T, op: F)
+where
+    F: FnOnce(Cell<&'a ()>, T),
+{
+    op(cell, t)
+}
+
+fn require<'a, 'b, T>(_cell: Cell<&'a ()>, _t: T)
+where
+    T: Anything<'b>,
+    T::AssocType: 'a,
+{
+}
+
+#[rustc_regions]
+fn no_relationships_late<'a, 'b, T>(cell: Cell<&'a ()>, t: T)
+where
+    T: Anything<'b>,
+{
+    with_signature(cell, t, |cell, t| require(cell, t));
+    //~^ WARNING not reporting region error due to -Znll
+    //~| ERROR failed type test
+    //~| ERROR free region `ReEarlyBound(0, 'b)` does not outlive free region `'_#2r`
+}
+
+#[rustc_regions]
+fn no_relationships_early<'a, 'b, T>(cell: Cell<&'a ()>, t: T)
+where
+    T: Anything<'b>,
+    'a: 'a,
+{
+    with_signature(cell, t, |cell, t| require(cell, t));
+    //~^ WARNING not reporting region error due to -Znll
+    //~| ERROR failed type test
+    //~| ERROR free region `ReEarlyBound(1, 'b)` does not outlive free region `ReEarlyBound(0, 'a)`
+}
+
+#[rustc_regions]
+fn projection_outlives<'a, 'b, T>(cell: Cell<&'a ()>, t: T)
+where
+    T: Anything<'b>,
+    T::AssocType: 'a,
+{
+    // This error is unfortunate. This code ought to type-check: we
+    // are projecting `<T as Anything<'b>>::AssocType`, and we know
+    // that this outlives `'a` because of the where-clause. However,
+    // the way the region checker works, we don't register this
+    // outlives obligation, and hence we get an error: this is because
+    // what we see is a projection like `<T as
+    // Anything<'?0>>::AssocType`, and we don't yet know if `?0` will
+    // equal `'b` or not, so we ignore the where-clause. Obviously we
+    // can do better here with a more involved verification step.
+
+    with_signature(cell, t, |cell, t| require(cell, t));
+    //~^ WARNING not reporting region error due to -Znll
+    //~| ERROR failed type test
+    //~| ERROR free region `ReEarlyBound(1, 'b)` does not outlive free region `ReEarlyBound(0, 'a)`
+}
+
+#[rustc_regions]
+fn elements_outlive<'a, 'b, T>(cell: Cell<&'a ()>, t: T)
+where
+    T: Anything<'b>,
+    T: 'a,
+    'b: 'a,
+{
+    with_signature(cell, t, |cell, t| require(cell, t));
+}
+
+fn main() {}
diff --git a/src/test/ui/nll/ty-outlives/projection-one-region-closure.stderr b/src/test/ui/nll/ty-outlives/projection-one-region-closure.stderr
new file mode 100644
index 00000000000..d187a094ec6
--- /dev/null
+++ b/src/test/ui/nll/ty-outlives/projection-one-region-closure.stderr
@@ -0,0 +1,194 @@
+warning: not reporting region error due to -Znll
+  --> $DIR/projection-one-region-closure.rs:56:39
+   |
+56 |     with_signature(cell, t, |cell, t| require(cell, t));
+   |                                       ^^^^^^^
+
+warning: not reporting region error due to -Znll
+  --> $DIR/projection-one-region-closure.rs:68:39
+   |
+68 |     with_signature(cell, t, |cell, t| require(cell, t));
+   |                                       ^^^^^^^
+
+warning: not reporting region error due to -Znll
+  --> $DIR/projection-one-region-closure.rs:90:39
+   |
+90 |     with_signature(cell, t, |cell, t| require(cell, t));
+   |                                       ^^^^^^^
+
+note: External requirements
+  --> $DIR/projection-one-region-closure.rs:56:29
+   |
+56 |     with_signature(cell, t, |cell, t| require(cell, t));
+   |                             ^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: defining type: DefId(0/1:19 ~ projection_one_region_closure[317d]::no_relationships_late[0]::{{closure}}[0]) with closure substs [
+               '_#1r,
+               T,
+               i32,
+               extern "rust-call" fn((std::cell::Cell<&'_#2r ()>, T))
+           ]
+   = note: number of external vids: 3
+   = note: where T: '_#2r
+   = note: where '_#1r: '_#2r
+
+note: External requirements
+  --> $DIR/projection-one-region-closure.rs:68:29
+   |
+68 |     with_signature(cell, t, |cell, t| require(cell, t));
+   |                             ^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: defining type: DefId(0/1:23 ~ projection_one_region_closure[317d]::no_relationships_early[0]::{{closure}}[0]) with closure substs [
+               '_#1r,
+               '_#2r,
+               T,
+               i32,
+               extern "rust-call" fn((std::cell::Cell<&'_#3r ()>, T))
+           ]
+   = note: number of external vids: 4
+   = note: where T: '_#3r
+   = note: where '_#2r: '_#3r
+
+note: External requirements
+  --> $DIR/projection-one-region-closure.rs:90:29
+   |
+90 |     with_signature(cell, t, |cell, t| require(cell, t));
+   |                             ^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: defining type: DefId(0/1:27 ~ projection_one_region_closure[317d]::projection_outlives[0]::{{closure}}[0]) with closure substs [
+               '_#1r,
+               '_#2r,
+               T,
+               i32,
+               extern "rust-call" fn((std::cell::Cell<&'_#3r ()>, T))
+           ]
+   = note: number of external vids: 4
+   = note: where T: '_#3r
+   = note: where '_#2r: '_#3r
+
+note: External requirements
+   --> $DIR/projection-one-region-closure.rs:103:29
+    |
+103 |     with_signature(cell, t, |cell, t| require(cell, t));
+    |                             ^^^^^^^^^^^^^^^^^^^^^^^^^^
+    |
+    = note: defining type: DefId(0/1:31 ~ projection_one_region_closure[317d]::elements_outlive[0]::{{closure}}[0]) with closure substs [
+                '_#1r,
+                '_#2r,
+                T,
+                i32,
+                extern "rust-call" fn((std::cell::Cell<&'_#3r ()>, T))
+            ]
+    = note: number of external vids: 4
+    = note: where T: '_#3r
+    = note: where '_#2r: '_#3r
+
+error: failed type test: TypeTest { generic_kind: T/#1, lower_bound: '_#5r, point: bb0[5], span: $DIR/projection-one-region-closure.rs:56:29: 56:55, test: IsOutlivedByAnyRegionIn(['_#3r]) }
+  --> $DIR/projection-one-region-closure.rs:56:29
+   |
+56 |     with_signature(cell, t, |cell, t| require(cell, t));
+   |                             ^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: free region `ReEarlyBound(0, 'b)` does not outlive free region `'_#2r`
+  --> $DIR/projection-one-region-closure.rs:56:20
+   |
+56 |     with_signature(cell, t, |cell, t| require(cell, t));
+   |                    ^^^^
+
+note: No external requirements
+  --> $DIR/projection-one-region-closure.rs:52:1
+   |
+52 | / fn no_relationships_late<'a, 'b, T>(cell: Cell<&'a ()>, t: T)
+53 | | where
+54 | |     T: Anything<'b>,
+55 | | {
+...  |
+59 | |     //~| ERROR free region `ReEarlyBound(0, 'b)` does not outlive free region `'_#2r`
+60 | | }
+   | |_^
+   |
+   = note: defining type: DefId(0/0:8 ~ projection_one_region_closure[317d]::no_relationships_late[0]) with substs [
+               '_#1r,
+               T
+           ]
+
+error: failed type test: TypeTest { generic_kind: T/#2, lower_bound: '_#6r, point: bb0[5], span: $DIR/projection-one-region-closure.rs:68:29: 68:55, test: IsOutlivedByAnyRegionIn(['_#3r]) }
+  --> $DIR/projection-one-region-closure.rs:68:29
+   |
+68 |     with_signature(cell, t, |cell, t| require(cell, t));
+   |                             ^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: free region `ReEarlyBound(1, 'b)` does not outlive free region `ReEarlyBound(0, 'a)`
+  --> $DIR/projection-one-region-closure.rs:68:20
+   |
+68 |     with_signature(cell, t, |cell, t| require(cell, t));
+   |                    ^^^^
+
+note: No external requirements
+  --> $DIR/projection-one-region-closure.rs:63:1
+   |
+63 | / fn no_relationships_early<'a, 'b, T>(cell: Cell<&'a ()>, t: T)
+64 | | where
+65 | |     T: Anything<'b>,
+66 | |     'a: 'a,
+...  |
+71 | |     //~| ERROR free region `ReEarlyBound(1, 'b)` does not outlive free region `ReEarlyBound(0, 'a)`
+72 | | }
+   | |_^
+   |
+   = note: defining type: DefId(0/0:9 ~ projection_one_region_closure[317d]::no_relationships_early[0]) with substs [
+               '_#1r,
+               '_#2r,
+               T
+           ]
+
+error: failed type test: TypeTest { generic_kind: T/#2, lower_bound: '_#6r, point: bb0[5], span: $DIR/projection-one-region-closure.rs:90:29: 90:55, test: IsOutlivedByAnyRegionIn(['_#3r]) }
+  --> $DIR/projection-one-region-closure.rs:90:29
+   |
+90 |     with_signature(cell, t, |cell, t| require(cell, t));
+   |                             ^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: free region `ReEarlyBound(1, 'b)` does not outlive free region `ReEarlyBound(0, 'a)`
+  --> $DIR/projection-one-region-closure.rs:90:20
+   |
+90 |     with_signature(cell, t, |cell, t| require(cell, t));
+   |                    ^^^^
+
+note: No external requirements
+  --> $DIR/projection-one-region-closure.rs:75:1
+   |
+75 | / fn projection_outlives<'a, 'b, T>(cell: Cell<&'a ()>, t: T)
+76 | | where
+77 | |     T: Anything<'b>,
+78 | |     T::AssocType: 'a,
+...  |
+93 | |     //~| ERROR free region `ReEarlyBound(1, 'b)` does not outlive free region `ReEarlyBound(0, 'a)`
+94 | | }
+   | |_^
+   |
+   = note: defining type: DefId(0/0:10 ~ projection_one_region_closure[317d]::projection_outlives[0]) with substs [
+               '_#1r,
+               '_#2r,
+               T
+           ]
+
+note: No external requirements
+   --> $DIR/projection-one-region-closure.rs:97:1
+    |
+97  | / fn elements_outlive<'a, 'b, T>(cell: Cell<&'a ()>, t: T)
+98  | | where
+99  | |     T: Anything<'b>,
+100 | |     T: 'a,
+...   |
+103 | |     with_signature(cell, t, |cell, t| require(cell, t));
+104 | | }
+    | |_^
+    |
+    = note: defining type: DefId(0/0:11 ~ projection_one_region_closure[317d]::elements_outlive[0]) with substs [
+                '_#1r,
+                '_#2r,
+                T
+            ]
+
+error: aborting due to 6 previous errors
+
diff --git a/src/test/ui/nll/ty-outlives/projection-one-region-trait-bound-closure.rs b/src/test/ui/nll/ty-outlives/projection-one-region-trait-bound-closure.rs
new file mode 100644
index 00000000000..e179927dfb0
--- /dev/null
+++ b/src/test/ui/nll/ty-outlives/projection-one-region-trait-bound-closure.rs
@@ -0,0 +1,106 @@
+// Copyright 2016 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.
+
+// Test cases where we constrain `<T as Anything<'b>>::AssocType` to
+// outlive `'a` and there is a unique bound in the trait definition of
+// `Anything` -- i.e., we know that `AssocType` outlives `'b`. In this
+// case, the best way to satisfy the trait bound is to show that `'b:
+// 'a`, which can be done in various ways.
+
+// compile-flags:-Znll -Zborrowck=mir -Zverbose
+
+#![allow(warnings)]
+#![feature(dyn_trait)]
+#![feature(rustc_attrs)]
+
+use std::cell::Cell;
+
+trait Anything<'a> {
+    type AssocType: 'a;
+}
+
+fn with_signature<'a, T, F>(cell: Cell<&'a ()>, t: T, op: F)
+where
+    F: FnOnce(Cell<&'a ()>, T),
+{
+    op(cell, t)
+}
+
+fn require<'a, 'b, T>(_cell: Cell<&'a ()>, _t: T)
+where
+    T: Anything<'b>,
+    T::AssocType: 'a,
+{
+}
+
+#[rustc_regions]
+fn no_relationships_late<'a, 'b, T>(cell: Cell<&'a ()>, t: T)
+where
+    T: Anything<'b>,
+{
+    with_signature(cell, t, |cell, t| require(cell, t));
+    //~^ WARNING not reporting region error due to -Znll
+    //~| ERROR free region `ReEarlyBound(0, 'b)` does not outlive free region `'_#2r`
+}
+
+#[rustc_regions]
+fn no_relationships_early<'a, 'b, T>(cell: Cell<&'a ()>, t: T)
+where
+    T: Anything<'b>,
+    'a: 'a,
+{
+    with_signature(cell, t, |cell, t| require(cell, t));
+    //~^ WARNING not reporting region error due to -Znll
+    //~| ERROR free region `ReEarlyBound(1, 'b)` does not outlive free region `ReEarlyBound(0, 'a)`
+}
+
+#[rustc_regions]
+fn projection_outlives<'a, 'b, T>(cell: Cell<&'a ()>, t: T)
+where
+    T: Anything<'b>,
+    T::AssocType: 'a,
+{
+    // This error is unfortunate. This code ought to type-check: we
+    // are projecting `<T as Anything<'b>>::AssocType`, and we know
+    // that this outlives `'a` because of the where-clause. However,
+    // the way the region checker works, we don't register this
+    // outlives obligation, and hence we get an error: this is because
+    // what we see is a projection like `<T as
+    // Anything<'?0>>::AssocType`, and we don't yet know if `?0` will
+    // equal `'b` or not, so we ignore the where-clause. Obviously we
+    // can do better here with a more involved verification step.
+
+    with_signature(cell, t, |cell, t| require(cell, t));
+    //~^ WARNING not reporting region error due to -Znll
+    //~| ERROR free region `ReEarlyBound(1, 'b)` does not outlive free region `ReEarlyBound(0, 'a)`
+}
+
+#[rustc_regions]
+fn elements_outlive<'a, 'b, T>(cell: Cell<&'a ()>, t: T)
+where
+    T: Anything<'b>,
+    'b: 'a,
+{
+    with_signature(cell, t, |cell, t| require(cell, t));
+}
+
+#[rustc_regions]
+fn one_region<'a, T>(cell: Cell<&'a ()>, t: T)
+where
+    T: Anything<'a>,
+{
+    // Note that in this case the closure still propagates an external
+    // requirement between two variables in its signature, but the
+    // creator maps both those two region variables to `'a` on its
+    // side.
+    with_signature(cell, t, |cell, t| require(cell, t));
+}
+
+fn main() {}
diff --git a/src/test/ui/nll/ty-outlives/projection-one-region-trait-bound-closure.stderr b/src/test/ui/nll/ty-outlives/projection-one-region-trait-bound-closure.stderr
new file mode 100644
index 00000000000..1088ae846fe
--- /dev/null
+++ b/src/test/ui/nll/ty-outlives/projection-one-region-trait-bound-closure.stderr
@@ -0,0 +1,204 @@
+warning: not reporting region error due to -Znll
+  --> $DIR/projection-one-region-trait-bound-closure.rs:48:39
+   |
+48 |     with_signature(cell, t, |cell, t| require(cell, t));
+   |                                       ^^^^^^^
+
+warning: not reporting region error due to -Znll
+  --> $DIR/projection-one-region-trait-bound-closure.rs:59:39
+   |
+59 |     with_signature(cell, t, |cell, t| require(cell, t));
+   |                                       ^^^^^^^
+
+warning: not reporting region error due to -Znll
+  --> $DIR/projection-one-region-trait-bound-closure.rs:80:39
+   |
+80 |     with_signature(cell, t, |cell, t| require(cell, t));
+   |                                       ^^^^^^^
+
+note: External requirements
+  --> $DIR/projection-one-region-trait-bound-closure.rs:48:29
+   |
+48 |     with_signature(cell, t, |cell, t| require(cell, t));
+   |                             ^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: defining type: DefId(0/1:19 ~ projection_one_region_trait_bound_closure[317d]::no_relationships_late[0]::{{closure}}[0]) with closure substs [
+               '_#1r,
+               T,
+               i32,
+               extern "rust-call" fn((std::cell::Cell<&'_#2r ()>, T))
+           ]
+   = note: number of external vids: 3
+   = note: where '_#1r: '_#2r
+
+note: External requirements
+  --> $DIR/projection-one-region-trait-bound-closure.rs:59:29
+   |
+59 |     with_signature(cell, t, |cell, t| require(cell, t));
+   |                             ^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: defining type: DefId(0/1:23 ~ projection_one_region_trait_bound_closure[317d]::no_relationships_early[0]::{{closure}}[0]) with closure substs [
+               '_#1r,
+               '_#2r,
+               T,
+               i32,
+               extern "rust-call" fn((std::cell::Cell<&'_#3r ()>, T))
+           ]
+   = note: number of external vids: 4
+   = note: where '_#2r: '_#3r
+
+note: External requirements
+  --> $DIR/projection-one-region-trait-bound-closure.rs:80:29
+   |
+80 |     with_signature(cell, t, |cell, t| require(cell, t));
+   |                             ^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: defining type: DefId(0/1:27 ~ projection_one_region_trait_bound_closure[317d]::projection_outlives[0]::{{closure}}[0]) with closure substs [
+               '_#1r,
+               '_#2r,
+               T,
+               i32,
+               extern "rust-call" fn((std::cell::Cell<&'_#3r ()>, T))
+           ]
+   = note: number of external vids: 4
+   = note: where '_#2r: '_#3r
+
+note: External requirements
+  --> $DIR/projection-one-region-trait-bound-closure.rs:91:29
+   |
+91 |     with_signature(cell, t, |cell, t| require(cell, t));
+   |                             ^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: defining type: DefId(0/1:31 ~ projection_one_region_trait_bound_closure[317d]::elements_outlive[0]::{{closure}}[0]) with closure substs [
+               '_#1r,
+               '_#2r,
+               T,
+               i32,
+               extern "rust-call" fn((std::cell::Cell<&'_#3r ()>, T))
+           ]
+   = note: number of external vids: 4
+   = note: where '_#2r: '_#3r
+
+note: External requirements
+   --> $DIR/projection-one-region-trait-bound-closure.rs:103:29
+    |
+103 |     with_signature(cell, t, |cell, t| require(cell, t));
+    |                             ^^^^^^^^^^^^^^^^^^^^^^^^^^
+    |
+    = note: defining type: DefId(0/1:34 ~ projection_one_region_trait_bound_closure[317d]::one_region[0]::{{closure}}[0]) with closure substs [
+                '_#1r,
+                T,
+                i32,
+                extern "rust-call" fn((std::cell::Cell<&'_#2r ()>, T))
+            ]
+    = note: number of external vids: 3
+    = note: where '_#1r: '_#2r
+
+error: free region `ReEarlyBound(0, 'b)` does not outlive free region `'_#2r`
+  --> $DIR/projection-one-region-trait-bound-closure.rs:48:20
+   |
+48 |     with_signature(cell, t, |cell, t| require(cell, t));
+   |                    ^^^^
+
+note: No external requirements
+  --> $DIR/projection-one-region-trait-bound-closure.rs:44:1
+   |
+44 | / fn no_relationships_late<'a, 'b, T>(cell: Cell<&'a ()>, t: T)
+45 | | where
+46 | |     T: Anything<'b>,
+47 | | {
+...  |
+50 | |     //~| ERROR free region `ReEarlyBound(0, 'b)` does not outlive free region `'_#2r`
+51 | | }
+   | |_^
+   |
+   = note: defining type: DefId(0/0:8 ~ projection_one_region_trait_bound_closure[317d]::no_relationships_late[0]) with substs [
+               '_#1r,
+               T
+           ]
+
+error: free region `ReEarlyBound(1, 'b)` does not outlive free region `ReEarlyBound(0, 'a)`
+  --> $DIR/projection-one-region-trait-bound-closure.rs:59:20
+   |
+59 |     with_signature(cell, t, |cell, t| require(cell, t));
+   |                    ^^^^
+
+note: No external requirements
+  --> $DIR/projection-one-region-trait-bound-closure.rs:54:1
+   |
+54 | / fn no_relationships_early<'a, 'b, T>(cell: Cell<&'a ()>, t: T)
+55 | | where
+56 | |     T: Anything<'b>,
+57 | |     'a: 'a,
+...  |
+61 | |     //~| ERROR free region `ReEarlyBound(1, 'b)` does not outlive free region `ReEarlyBound(0, 'a)`
+62 | | }
+   | |_^
+   |
+   = note: defining type: DefId(0/0:9 ~ projection_one_region_trait_bound_closure[317d]::no_relationships_early[0]) with substs [
+               '_#1r,
+               '_#2r,
+               T
+           ]
+
+error: free region `ReEarlyBound(1, 'b)` does not outlive free region `ReEarlyBound(0, 'a)`
+  --> $DIR/projection-one-region-trait-bound-closure.rs:80:20
+   |
+80 |     with_signature(cell, t, |cell, t| require(cell, t));
+   |                    ^^^^
+
+note: No external requirements
+  --> $DIR/projection-one-region-trait-bound-closure.rs:65:1
+   |
+65 | / fn projection_outlives<'a, 'b, T>(cell: Cell<&'a ()>, t: T)
+66 | | where
+67 | |     T: Anything<'b>,
+68 | |     T::AssocType: 'a,
+...  |
+82 | |     //~| ERROR free region `ReEarlyBound(1, 'b)` does not outlive free region `ReEarlyBound(0, 'a)`
+83 | | }
+   | |_^
+   |
+   = note: defining type: DefId(0/0:10 ~ projection_one_region_trait_bound_closure[317d]::projection_outlives[0]) with substs [
+               '_#1r,
+               '_#2r,
+               T
+           ]
+
+note: No external requirements
+  --> $DIR/projection-one-region-trait-bound-closure.rs:86:1
+   |
+86 | / fn elements_outlive<'a, 'b, T>(cell: Cell<&'a ()>, t: T)
+87 | | where
+88 | |     T: Anything<'b>,
+89 | |     'b: 'a,
+90 | | {
+91 | |     with_signature(cell, t, |cell, t| require(cell, t));
+92 | | }
+   | |_^
+   |
+   = note: defining type: DefId(0/0:11 ~ projection_one_region_trait_bound_closure[317d]::elements_outlive[0]) with substs [
+               '_#1r,
+               '_#2r,
+               T
+           ]
+
+note: No external requirements
+   --> $DIR/projection-one-region-trait-bound-closure.rs:95:1
+    |
+95  | / fn one_region<'a, T>(cell: Cell<&'a ()>, t: T)
+96  | | where
+97  | |     T: Anything<'a>,
+98  | | {
+...   |
+103 | |     with_signature(cell, t, |cell, t| require(cell, t));
+104 | | }
+    | |_^
+    |
+    = note: defining type: DefId(0/0:12 ~ projection_one_region_trait_bound_closure[317d]::one_region[0]) with substs [
+                '_#1r,
+                T
+            ]
+
+error: aborting due to 3 previous errors
+
diff --git a/src/test/ui/nll/ty-outlives/projection-one-region-trait-bound-static-closure.rs b/src/test/ui/nll/ty-outlives/projection-one-region-trait-bound-static-closure.rs
new file mode 100644
index 00000000000..67e28af1146
--- /dev/null
+++ b/src/test/ui/nll/ty-outlives/projection-one-region-trait-bound-static-closure.rs
@@ -0,0 +1,99 @@
+// Copyright 2016 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.
+
+// Test cases where we constrain `<T as Anything<'b>>::AssocType` to
+// outlive `'static`. In this case, we don't get any errors, and in fact
+// we don't even propagate constraints from the closures to the callers.
+
+// compile-flags:-Znll -Zborrowck=mir -Zverbose
+// must-compile-successfully
+
+#![allow(warnings)]
+#![feature(dyn_trait)]
+#![feature(rustc_attrs)]
+
+use std::cell::Cell;
+
+trait Anything<'a> {
+    type AssocType: 'static;
+}
+
+fn with_signature<'a, T, F>(cell: Cell<&'a ()>, t: T, op: F)
+where
+    F: FnOnce(Cell<&'a ()>, T),
+{
+    op(cell, t)
+}
+
+fn require<'a, 'b, T>(_cell: Cell<&'a ()>, _t: T)
+where
+    T: Anything<'b>,
+    T::AssocType: 'a,
+{
+}
+
+#[rustc_regions]
+fn no_relationships_late<'a, 'b, T>(cell: Cell<&'a ()>, t: T)
+where
+    T: Anything<'b>,
+{
+    with_signature(cell, t, |cell, t| require(cell, t));
+}
+
+#[rustc_regions]
+fn no_relationships_early<'a, 'b, T>(cell: Cell<&'a ()>, t: T)
+where
+    T: Anything<'b>,
+    'a: 'a,
+{
+    with_signature(cell, t, |cell, t| require(cell, t));
+}
+
+#[rustc_regions]
+fn projection_outlives<'a, 'b, T>(cell: Cell<&'a ()>, t: T)
+where
+    T: Anything<'b>,
+    T::AssocType: 'a,
+{
+    // This error is unfortunate. This code ought to type-check: we
+    // are projecting `<T as Anything<'b>>::AssocType`, and we know
+    // that this outlives `'a` because of the where-clause. However,
+    // the way the region checker works, we don't register this
+    // outlives obligation, and hence we get an error: this is because
+    // what we see is a projection like `<T as
+    // Anything<'?0>>::AssocType`, and we don't yet know if `?0` will
+    // equal `'b` or not, so we ignore the where-clause. Obviously we
+    // can do better here with a more involved verification step.
+
+    with_signature(cell, t, |cell, t| require(cell, t));
+}
+
+#[rustc_regions]
+fn elements_outlive<'a, 'b, T>(cell: Cell<&'a ()>, t: T)
+where
+    T: Anything<'b>,
+    'b: 'a,
+{
+    with_signature(cell, t, |cell, t| require(cell, t));
+}
+
+#[rustc_regions]
+fn one_region<'a, T>(cell: Cell<&'a ()>, t: T)
+where
+    T: Anything<'a>,
+{
+    // Note that in this case the closure still propagates an external
+    // requirement between two variables in its signature, but the
+    // creator maps both those two region variables to `'a` on its
+    // side.
+    with_signature(cell, t, |cell, t| require(cell, t));
+}
+
+fn main() {}
diff --git a/src/test/ui/nll/ty-outlives/projection-one-region-trait-bound-static-closure.stderr b/src/test/ui/nll/ty-outlives/projection-one-region-trait-bound-static-closure.stderr
new file mode 100644
index 00000000000..986676d28d9
--- /dev/null
+++ b/src/test/ui/nll/ty-outlives/projection-one-region-trait-bound-static-closure.stderr
@@ -0,0 +1,155 @@
+note: No external requirements
+  --> $DIR/projection-one-region-trait-bound-static-closure.rs:47:29
+   |
+47 |     with_signature(cell, t, |cell, t| require(cell, t));
+   |                             ^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: defining type: DefId(0/1:19 ~ projection_one_region_trait_bound_static_closure[317d]::no_relationships_late[0]::{{closure}}[0]) with closure substs [
+               '_#1r,
+               T,
+               i32,
+               extern "rust-call" fn((std::cell::Cell<&'_#2r ()>, T))
+           ]
+
+note: No external requirements
+  --> $DIR/projection-one-region-trait-bound-static-closure.rs:56:29
+   |
+56 |     with_signature(cell, t, |cell, t| require(cell, t));
+   |                             ^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: defining type: DefId(0/1:23 ~ projection_one_region_trait_bound_static_closure[317d]::no_relationships_early[0]::{{closure}}[0]) with closure substs [
+               '_#1r,
+               '_#2r,
+               T,
+               i32,
+               extern "rust-call" fn((std::cell::Cell<&'_#3r ()>, T))
+           ]
+
+note: No external requirements
+  --> $DIR/projection-one-region-trait-bound-static-closure.rs:75:29
+   |
+75 |     with_signature(cell, t, |cell, t| require(cell, t));
+   |                             ^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: defining type: DefId(0/1:27 ~ projection_one_region_trait_bound_static_closure[317d]::projection_outlives[0]::{{closure}}[0]) with closure substs [
+               '_#1r,
+               '_#2r,
+               T,
+               i32,
+               extern "rust-call" fn((std::cell::Cell<&'_#3r ()>, T))
+           ]
+
+note: No external requirements
+  --> $DIR/projection-one-region-trait-bound-static-closure.rs:84:29
+   |
+84 |     with_signature(cell, t, |cell, t| require(cell, t));
+   |                             ^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: defining type: DefId(0/1:31 ~ projection_one_region_trait_bound_static_closure[317d]::elements_outlive[0]::{{closure}}[0]) with closure substs [
+               '_#1r,
+               '_#2r,
+               T,
+               i32,
+               extern "rust-call" fn((std::cell::Cell<&'_#3r ()>, T))
+           ]
+
+note: No external requirements
+  --> $DIR/projection-one-region-trait-bound-static-closure.rs:96:29
+   |
+96 |     with_signature(cell, t, |cell, t| require(cell, t));
+   |                             ^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: defining type: DefId(0/1:34 ~ projection_one_region_trait_bound_static_closure[317d]::one_region[0]::{{closure}}[0]) with closure substs [
+               '_#1r,
+               T,
+               i32,
+               extern "rust-call" fn((std::cell::Cell<&'_#2r ()>, T))
+           ]
+
+note: No external requirements
+  --> $DIR/projection-one-region-trait-bound-static-closure.rs:43:1
+   |
+43 | / fn no_relationships_late<'a, 'b, T>(cell: Cell<&'a ()>, t: T)
+44 | | where
+45 | |     T: Anything<'b>,
+46 | | {
+47 | |     with_signature(cell, t, |cell, t| require(cell, t));
+48 | | }
+   | |_^
+   |
+   = note: defining type: DefId(0/0:8 ~ projection_one_region_trait_bound_static_closure[317d]::no_relationships_late[0]) with substs [
+               '_#1r,
+               T
+           ]
+
+note: No external requirements
+  --> $DIR/projection-one-region-trait-bound-static-closure.rs:51:1
+   |
+51 | / fn no_relationships_early<'a, 'b, T>(cell: Cell<&'a ()>, t: T)
+52 | | where
+53 | |     T: Anything<'b>,
+54 | |     'a: 'a,
+55 | | {
+56 | |     with_signature(cell, t, |cell, t| require(cell, t));
+57 | | }
+   | |_^
+   |
+   = note: defining type: DefId(0/0:9 ~ projection_one_region_trait_bound_static_closure[317d]::no_relationships_early[0]) with substs [
+               '_#1r,
+               '_#2r,
+               T
+           ]
+
+note: No external requirements
+  --> $DIR/projection-one-region-trait-bound-static-closure.rs:60:1
+   |
+60 | / fn projection_outlives<'a, 'b, T>(cell: Cell<&'a ()>, t: T)
+61 | | where
+62 | |     T: Anything<'b>,
+63 | |     T::AssocType: 'a,
+...  |
+75 | |     with_signature(cell, t, |cell, t| require(cell, t));
+76 | | }
+   | |_^
+   |
+   = note: defining type: DefId(0/0:10 ~ projection_one_region_trait_bound_static_closure[317d]::projection_outlives[0]) with substs [
+               '_#1r,
+               '_#2r,
+               T
+           ]
+
+note: No external requirements
+  --> $DIR/projection-one-region-trait-bound-static-closure.rs:79:1
+   |
+79 | / fn elements_outlive<'a, 'b, T>(cell: Cell<&'a ()>, t: T)
+80 | | where
+81 | |     T: Anything<'b>,
+82 | |     'b: 'a,
+83 | | {
+84 | |     with_signature(cell, t, |cell, t| require(cell, t));
+85 | | }
+   | |_^
+   |
+   = note: defining type: DefId(0/0:11 ~ projection_one_region_trait_bound_static_closure[317d]::elements_outlive[0]) with substs [
+               '_#1r,
+               '_#2r,
+               T
+           ]
+
+note: No external requirements
+  --> $DIR/projection-one-region-trait-bound-static-closure.rs:88:1
+   |
+88 | / fn one_region<'a, T>(cell: Cell<&'a ()>, t: T)
+89 | | where
+90 | |     T: Anything<'a>,
+91 | | {
+...  |
+96 | |     with_signature(cell, t, |cell, t| require(cell, t));
+97 | | }
+   | |_^
+   |
+   = note: defining type: DefId(0/0:12 ~ projection_one_region_trait_bound_static_closure[317d]::one_region[0]) with substs [
+               '_#1r,
+               T
+           ]
+
diff --git a/src/test/ui/nll/ty-outlives/projection-two-region-trait-bound-closure.rs b/src/test/ui/nll/ty-outlives/projection-two-region-trait-bound-closure.rs
new file mode 100644
index 00000000000..f8f3065fff4
--- /dev/null
+++ b/src/test/ui/nll/ty-outlives/projection-two-region-trait-bound-closure.rs
@@ -0,0 +1,135 @@
+// Copyright 2016 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.
+
+// Test cases where we constrain `<T as Anything<'a, 'b>>::AssocType`
+// to outlive `'a` and there are two bounds in the trait definition of
+// `Anything` -- i.e., we know that `AssocType` outlives `'a` and
+// `'b`. In this case, it's not clear what is the best way to satisfy
+// the trait bound, and hence we propagate it to the caller as a type
+// test.
+
+// compile-flags:-Znll -Zborrowck=mir -Zverbose
+
+#![allow(warnings)]
+#![feature(dyn_trait)]
+#![feature(rustc_attrs)]
+
+use std::cell::Cell;
+
+trait Anything<'a, 'b> {
+    type AssocType: 'a + 'b;
+}
+
+fn with_signature<'a, T, F>(cell: Cell<&'a ()>, t: T, op: F)
+where
+    F: FnOnce(Cell<&'a ()>, T),
+{
+    op(cell, t)
+}
+
+fn require<'a, 'b, 'c, T>(_cell: Cell<&'a ()>, _t: T)
+where
+    T: Anything<'b, 'c>,
+    T::AssocType: 'a,
+{
+}
+
+#[rustc_regions]
+fn no_relationships_late<'a, 'b, 'c, T>(cell: Cell<&'a ()>, t: T)
+where
+    T: Anything<'b, 'c>,
+{
+    with_signature(cell, t, |cell, t| require(cell, t));
+    //~^ WARNING not reporting region error due to -Znll
+    //~| ERROR failed type test
+}
+
+#[rustc_regions]
+fn no_relationships_early<'a, 'b, 'c, T>(cell: Cell<&'a ()>, t: T)
+where
+    T: Anything<'b, 'c>,
+    'a: 'a,
+{
+    with_signature(cell, t, |cell, t| require(cell, t));
+    //~^ WARNING not reporting region error due to -Znll
+    //~| ERROR failed type test
+}
+
+#[rustc_regions]
+fn projection_outlives<'a, 'b, 'c, T>(cell: Cell<&'a ()>, t: T)
+where
+    T: Anything<'b, 'c>,
+    T::AssocType: 'a,
+{
+    // This error is unfortunate. This code ought to type-check: we
+    // are projecting `<T as Anything<'b>>::AssocType`, and we know
+    // that this outlives `'a` because of the where-clause. However,
+    // the way the region checker works, we don't register this
+    // outlives obligation, and hence we get an error: this is because
+    // what we see is a projection like `<T as
+    // Anything<'?0>>::AssocType`, and we don't yet know if `?0` will
+    // equal `'b` or not, so we ignore the where-clause. Obviously we
+    // can do better here with a more involved verification step.
+
+    with_signature(cell, t, |cell, t| require(cell, t));
+    //~^ WARNING not reporting region error due to -Znll
+    //~| ERROR failed type test
+}
+
+#[rustc_regions]
+fn elements_outlive1<'a, 'b, 'c, T>(cell: Cell<&'a ()>, t: T)
+where
+    T: Anything<'b, 'c>,
+    'b: 'a,
+{
+    with_signature(cell, t, |cell, t| require(cell, t));
+}
+
+#[rustc_regions]
+fn elements_outlive2<'a, 'b, 'c, T>(cell: Cell<&'a ()>, t: T)
+where
+    T: Anything<'b, 'c>,
+    'c: 'a,
+{
+    with_signature(cell, t, |cell, t| require(cell, t));
+}
+
+#[rustc_regions]
+fn two_regions<'a, 'b, T>(cell: Cell<&'a ()>, t: T)
+where
+    T: Anything<'b, 'b>,
+{
+    with_signature(cell, t, |cell, t| require(cell, t));
+    //~^ WARNING not reporting region error due to -Znll
+    //~| ERROR free region `ReEarlyBound(0, 'b)` does not outlive free region `'_#2r`
+}
+
+#[rustc_regions]
+fn two_regions_outlive<'a, 'b, T>(cell: Cell<&'a ()>, t: T)
+where
+    T: Anything<'b, 'b>,
+    'b: 'a,
+{
+    with_signature(cell, t, |cell, t| require(cell, t));
+}
+
+#[rustc_regions]
+fn one_region<'a, T>(cell: Cell<&'a ()>, t: T)
+where
+    T: Anything<'a, 'a>,
+{
+    // Note that in this case the closure still propagates an external
+    // requirement between two variables in its signature, but the
+    // creator maps both those two region variables to `'a` on its
+    // side.
+    with_signature(cell, t, |cell, t| require(cell, t));
+}
+
+fn main() {}
diff --git a/src/test/ui/nll/ty-outlives/projection-two-region-trait-bound-closure.stderr b/src/test/ui/nll/ty-outlives/projection-two-region-trait-bound-closure.stderr
new file mode 100644
index 00000000000..02650214129
--- /dev/null
+++ b/src/test/ui/nll/ty-outlives/projection-two-region-trait-bound-closure.stderr
@@ -0,0 +1,326 @@
+warning: not reporting region error due to -Znll
+  --> $DIR/projection-two-region-trait-bound-closure.rs:49:39
+   |
+49 |     with_signature(cell, t, |cell, t| require(cell, t));
+   |                                       ^^^^^^^
+
+warning: not reporting region error due to -Znll
+  --> $DIR/projection-two-region-trait-bound-closure.rs:60:39
+   |
+60 |     with_signature(cell, t, |cell, t| require(cell, t));
+   |                                       ^^^^^^^
+
+warning: not reporting region error due to -Znll
+  --> $DIR/projection-two-region-trait-bound-closure.rs:81:39
+   |
+81 |     with_signature(cell, t, |cell, t| require(cell, t));
+   |                                       ^^^^^^^
+
+warning: not reporting region error due to -Znll
+   --> $DIR/projection-two-region-trait-bound-closure.rs:109:39
+    |
+109 |     with_signature(cell, t, |cell, t| require(cell, t));
+    |                                       ^^^^^^^
+
+note: External requirements
+  --> $DIR/projection-two-region-trait-bound-closure.rs:49:29
+   |
+49 |     with_signature(cell, t, |cell, t| require(cell, t));
+   |                             ^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: defining type: DefId(0/1:22 ~ projection_two_region_trait_bound_closure[317d]::no_relationships_late[0]::{{closure}}[0]) with closure substs [
+               '_#1r,
+               '_#2r,
+               T,
+               i32,
+               extern "rust-call" fn((std::cell::Cell<&'_#3r ()>, T))
+           ]
+   = note: number of external vids: 4
+   = note: where <T as Anything<ReClosureBound('_#1r), ReClosureBound('_#2r)>>::AssocType: '_#3r
+
+note: External requirements
+  --> $DIR/projection-two-region-trait-bound-closure.rs:60:29
+   |
+60 |     with_signature(cell, t, |cell, t| require(cell, t));
+   |                             ^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: defining type: DefId(0/1:27 ~ projection_two_region_trait_bound_closure[317d]::no_relationships_early[0]::{{closure}}[0]) with closure substs [
+               '_#1r,
+               '_#2r,
+               '_#3r,
+               T,
+               i32,
+               extern "rust-call" fn((std::cell::Cell<&'_#4r ()>, T))
+           ]
+   = note: number of external vids: 5
+   = note: where <T as Anything<ReClosureBound('_#2r), ReClosureBound('_#3r)>>::AssocType: '_#4r
+
+note: External requirements
+  --> $DIR/projection-two-region-trait-bound-closure.rs:81:29
+   |
+81 |     with_signature(cell, t, |cell, t| require(cell, t));
+   |                             ^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: defining type: DefId(0/1:32 ~ projection_two_region_trait_bound_closure[317d]::projection_outlives[0]::{{closure}}[0]) with closure substs [
+               '_#1r,
+               '_#2r,
+               '_#3r,
+               T,
+               i32,
+               extern "rust-call" fn((std::cell::Cell<&'_#4r ()>, T))
+           ]
+   = note: number of external vids: 5
+   = note: where <T as Anything<ReClosureBound('_#2r), ReClosureBound('_#3r)>>::AssocType: '_#4r
+
+note: External requirements
+  --> $DIR/projection-two-region-trait-bound-closure.rs:92:29
+   |
+92 |     with_signature(cell, t, |cell, t| require(cell, t));
+   |                             ^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: defining type: DefId(0/1:37 ~ projection_two_region_trait_bound_closure[317d]::elements_outlive1[0]::{{closure}}[0]) with closure substs [
+               '_#1r,
+               '_#2r,
+               '_#3r,
+               T,
+               i32,
+               extern "rust-call" fn((std::cell::Cell<&'_#4r ()>, T))
+           ]
+   = note: number of external vids: 5
+   = note: where <T as Anything<ReClosureBound('_#2r), ReClosureBound('_#3r)>>::AssocType: '_#4r
+
+note: External requirements
+   --> $DIR/projection-two-region-trait-bound-closure.rs:101:29
+    |
+101 |     with_signature(cell, t, |cell, t| require(cell, t));
+    |                             ^^^^^^^^^^^^^^^^^^^^^^^^^^
+    |
+    = note: defining type: DefId(0/1:42 ~ projection_two_region_trait_bound_closure[317d]::elements_outlive2[0]::{{closure}}[0]) with closure substs [
+                '_#1r,
+                '_#2r,
+                '_#3r,
+                T,
+                i32,
+                extern "rust-call" fn((std::cell::Cell<&'_#4r ()>, T))
+            ]
+    = note: number of external vids: 5
+    = note: where <T as Anything<ReClosureBound('_#2r), ReClosureBound('_#3r)>>::AssocType: '_#4r
+
+note: External requirements
+   --> $DIR/projection-two-region-trait-bound-closure.rs:109:29
+    |
+109 |     with_signature(cell, t, |cell, t| require(cell, t));
+    |                             ^^^^^^^^^^^^^^^^^^^^^^^^^^
+    |
+    = note: defining type: DefId(0/1:46 ~ projection_two_region_trait_bound_closure[317d]::two_regions[0]::{{closure}}[0]) with closure substs [
+                '_#1r,
+                T,
+                i32,
+                extern "rust-call" fn((std::cell::Cell<&'_#2r ()>, T))
+            ]
+    = note: number of external vids: 3
+    = note: where <T as Anything<ReClosureBound('_#1r), ReClosureBound('_#1r)>>::AssocType: '_#2r
+
+note: External requirements
+   --> $DIR/projection-two-region-trait-bound-closure.rs:120:29
+    |
+120 |     with_signature(cell, t, |cell, t| require(cell, t));
+    |                             ^^^^^^^^^^^^^^^^^^^^^^^^^^
+    |
+    = note: defining type: DefId(0/1:50 ~ projection_two_region_trait_bound_closure[317d]::two_regions_outlive[0]::{{closure}}[0]) with closure substs [
+                '_#1r,
+                '_#2r,
+                T,
+                i32,
+                extern "rust-call" fn((std::cell::Cell<&'_#3r ()>, T))
+            ]
+    = note: number of external vids: 4
+    = note: where <T as Anything<ReClosureBound('_#2r), ReClosureBound('_#2r)>>::AssocType: '_#3r
+
+note: External requirements
+   --> $DIR/projection-two-region-trait-bound-closure.rs:132:29
+    |
+132 |     with_signature(cell, t, |cell, t| require(cell, t));
+    |                             ^^^^^^^^^^^^^^^^^^^^^^^^^^
+    |
+    = note: defining type: DefId(0/1:53 ~ projection_two_region_trait_bound_closure[317d]::one_region[0]::{{closure}}[0]) with closure substs [
+                '_#1r,
+                T,
+                i32,
+                extern "rust-call" fn((std::cell::Cell<&'_#2r ()>, T))
+            ]
+    = note: number of external vids: 3
+    = note: where <T as Anything<ReClosureBound('_#1r), ReClosureBound('_#1r)>>::AssocType: '_#2r
+
+error: failed type test: TypeTest { generic_kind: ProjectionTy { substs: Slice([T, '_#5r, '_#6r]), item_def_id: DefId(0/0:5 ~ projection_two_region_trait_bound_closure[317d]::Anything[0]::AssocType[0]) }, lower_bound: '_#7r, point: bb0[5], span: $DIR/projection-two-region-trait-bound-closure.rs:49:29: 49:55, test: Any([IsOutlivedByAnyRegionIn(['_#6r, '_#5r]), All([IsOutlivedByAnyRegionIn(['_#4r]), IsOutlivedByAllRegionsIn(['_#5r, '_#6r])])]) }
+  --> $DIR/projection-two-region-trait-bound-closure.rs:49:29
+   |
+49 |     with_signature(cell, t, |cell, t| require(cell, t));
+   |                             ^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+note: No external requirements
+  --> $DIR/projection-two-region-trait-bound-closure.rs:45:1
+   |
+45 | / fn no_relationships_late<'a, 'b, 'c, T>(cell: Cell<&'a ()>, t: T)
+46 | | where
+47 | |     T: Anything<'b, 'c>,
+48 | | {
+...  |
+51 | |     //~| ERROR failed type test
+52 | | }
+   | |_^
+   |
+   = note: defining type: DefId(0/0:8 ~ projection_two_region_trait_bound_closure[317d]::no_relationships_late[0]) with substs [
+               '_#1r,
+               '_#2r,
+               T
+           ]
+
+error: failed type test: TypeTest { generic_kind: ProjectionTy { substs: Slice([T, '_#6r, '_#7r]), item_def_id: DefId(0/0:5 ~ projection_two_region_trait_bound_closure[317d]::Anything[0]::AssocType[0]) }, lower_bound: '_#8r, point: bb0[5], span: $DIR/projection-two-region-trait-bound-closure.rs:60:29: 60:55, test: Any([IsOutlivedByAnyRegionIn(['_#7r, '_#6r]), All([IsOutlivedByAnyRegionIn(['_#4r]), IsOutlivedByAllRegionsIn(['_#6r, '_#7r])])]) }
+  --> $DIR/projection-two-region-trait-bound-closure.rs:60:29
+   |
+60 |     with_signature(cell, t, |cell, t| require(cell, t));
+   |                             ^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+note: No external requirements
+  --> $DIR/projection-two-region-trait-bound-closure.rs:55:1
+   |
+55 | / fn no_relationships_early<'a, 'b, 'c, T>(cell: Cell<&'a ()>, t: T)
+56 | | where
+57 | |     T: Anything<'b, 'c>,
+58 | |     'a: 'a,
+...  |
+62 | |     //~| ERROR failed type test
+63 | | }
+   | |_^
+   |
+   = note: defining type: DefId(0/0:9 ~ projection_two_region_trait_bound_closure[317d]::no_relationships_early[0]) with substs [
+               '_#1r,
+               '_#2r,
+               '_#3r,
+               T
+           ]
+
+error: failed type test: TypeTest { generic_kind: ProjectionTy { substs: Slice([T, '_#6r, '_#7r]), item_def_id: DefId(0/0:5 ~ projection_two_region_trait_bound_closure[317d]::Anything[0]::AssocType[0]) }, lower_bound: '_#8r, point: bb0[5], span: $DIR/projection-two-region-trait-bound-closure.rs:81:29: 81:55, test: Any([IsOutlivedByAnyRegionIn(['_#7r, '_#6r]), All([IsOutlivedByAnyRegionIn(['_#4r]), IsOutlivedByAllRegionsIn(['_#6r, '_#7r])])]) }
+  --> $DIR/projection-two-region-trait-bound-closure.rs:81:29
+   |
+81 |     with_signature(cell, t, |cell, t| require(cell, t));
+   |                             ^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+note: No external requirements
+  --> $DIR/projection-two-region-trait-bound-closure.rs:66:1
+   |
+66 | / fn projection_outlives<'a, 'b, 'c, T>(cell: Cell<&'a ()>, t: T)
+67 | | where
+68 | |     T: Anything<'b, 'c>,
+69 | |     T::AssocType: 'a,
+...  |
+83 | |     //~| ERROR failed type test
+84 | | }
+   | |_^
+   |
+   = note: defining type: DefId(0/0:10 ~ projection_two_region_trait_bound_closure[317d]::projection_outlives[0]) with substs [
+               '_#1r,
+               '_#2r,
+               '_#3r,
+               T
+           ]
+
+note: No external requirements
+  --> $DIR/projection-two-region-trait-bound-closure.rs:87:1
+   |
+87 | / fn elements_outlive1<'a, 'b, 'c, T>(cell: Cell<&'a ()>, t: T)
+88 | | where
+89 | |     T: Anything<'b, 'c>,
+90 | |     'b: 'a,
+91 | | {
+92 | |     with_signature(cell, t, |cell, t| require(cell, t));
+93 | | }
+   | |_^
+   |
+   = note: defining type: DefId(0/0:11 ~ projection_two_region_trait_bound_closure[317d]::elements_outlive1[0]) with substs [
+               '_#1r,
+               '_#2r,
+               '_#3r,
+               T
+           ]
+
+note: No external requirements
+   --> $DIR/projection-two-region-trait-bound-closure.rs:96:1
+    |
+96  | / fn elements_outlive2<'a, 'b, 'c, T>(cell: Cell<&'a ()>, t: T)
+97  | | where
+98  | |     T: Anything<'b, 'c>,
+99  | |     'c: 'a,
+100 | | {
+101 | |     with_signature(cell, t, |cell, t| require(cell, t));
+102 | | }
+    | |_^
+    |
+    = note: defining type: DefId(0/0:12 ~ projection_two_region_trait_bound_closure[317d]::elements_outlive2[0]) with substs [
+                '_#1r,
+                '_#2r,
+                '_#3r,
+                T
+            ]
+
+error: free region `ReEarlyBound(0, 'b)` does not outlive free region `'_#2r`
+   --> $DIR/projection-two-region-trait-bound-closure.rs:109:20
+    |
+109 |     with_signature(cell, t, |cell, t| require(cell, t));
+    |                    ^^^^
+
+note: No external requirements
+   --> $DIR/projection-two-region-trait-bound-closure.rs:105:1
+    |
+105 | / fn two_regions<'a, 'b, T>(cell: Cell<&'a ()>, t: T)
+106 | | where
+107 | |     T: Anything<'b, 'b>,
+108 | | {
+...   |
+111 | |     //~| ERROR free region `ReEarlyBound(0, 'b)` does not outlive free region `'_#2r`
+112 | | }
+    | |_^
+    |
+    = note: defining type: DefId(0/0:13 ~ projection_two_region_trait_bound_closure[317d]::two_regions[0]) with substs [
+                '_#1r,
+                T
+            ]
+
+note: No external requirements
+   --> $DIR/projection-two-region-trait-bound-closure.rs:115:1
+    |
+115 | / fn two_regions_outlive<'a, 'b, T>(cell: Cell<&'a ()>, t: T)
+116 | | where
+117 | |     T: Anything<'b, 'b>,
+118 | |     'b: 'a,
+119 | | {
+120 | |     with_signature(cell, t, |cell, t| require(cell, t));
+121 | | }
+    | |_^
+    |
+    = note: defining type: DefId(0/0:14 ~ projection_two_region_trait_bound_closure[317d]::two_regions_outlive[0]) with substs [
+                '_#1r,
+                '_#2r,
+                T
+            ]
+
+note: No external requirements
+   --> $DIR/projection-two-region-trait-bound-closure.rs:124:1
+    |
+124 | / fn one_region<'a, T>(cell: Cell<&'a ()>, t: T)
+125 | | where
+126 | |     T: Anything<'a, 'a>,
+127 | | {
+...   |
+132 | |     with_signature(cell, t, |cell, t| require(cell, t));
+133 | | }
+    | |_^
+    |
+    = note: defining type: DefId(0/0:15 ~ projection_two_region_trait_bound_closure[317d]::one_region[0]) with substs [
+                '_#1r,
+                T
+            ]
+
+error: aborting due to 4 previous errors
+