summaryrefslogtreecommitdiffstats
path: root/tests/ui/nll/closure-requirements
diff options
context:
space:
mode:
Diffstat (limited to 'tests/ui/nll/closure-requirements')
-rw-r--r--tests/ui/nll/closure-requirements/escape-argument-callee.rs42
-rw-r--r--tests/ui/nll/closure-requirements/escape-argument-callee.stderr31
-rw-r--r--tests/ui/nll/closure-requirements/escape-argument.rs42
-rw-r--r--tests/ui/nll/closure-requirements/escape-argument.stderr35
-rw-r--r--tests/ui/nll/closure-requirements/escape-upvar-nested.rs33
-rw-r--r--tests/ui/nll/closure-requirements/escape-upvar-nested.stderr53
-rw-r--r--tests/ui/nll/closure-requirements/escape-upvar-ref.rs33
-rw-r--r--tests/ui/nll/closure-requirements/escape-upvar-ref.stderr39
-rw-r--r--tests/ui/nll/closure-requirements/issue-58127-mutliple-requirements.rs36
-rw-r--r--tests/ui/nll/closure-requirements/propagate-approximated-fail-no-postdom.rs51
-rw-r--r--tests/ui/nll/closure-requirements/propagate-approximated-fail-no-postdom.stderr36
-rw-r--r--tests/ui/nll/closure-requirements/propagate-approximated-ref.rs50
-rw-r--r--tests/ui/nll/closure-requirements/propagate-approximated-ref.stderr39
-rw-r--r--tests/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-comparing-against-free.rs40
-rw-r--r--tests/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-comparing-against-free.stderr69
-rw-r--r--tests/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-no-bound.rs40
-rw-r--r--tests/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-no-bound.stderr49
-rw-r--r--tests/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-wrong-bound.rs43
-rw-r--r--tests/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-wrong-bound.stderr49
-rw-r--r--tests/ui/nll/closure-requirements/propagate-approximated-val.rs43
-rw-r--r--tests/ui/nll/closure-requirements/propagate-approximated-val.stderr39
-rw-r--r--tests/ui/nll/closure-requirements/propagate-despite-same-free-region.rs50
-rw-r--r--tests/ui/nll/closure-requirements/propagate-despite-same-free-region.stderr23
-rw-r--r--tests/ui/nll/closure-requirements/propagate-fail-to-approximate-longer-no-bounds.rs42
-rw-r--r--tests/ui/nll/closure-requirements/propagate-fail-to-approximate-longer-no-bounds.stderr35
-rw-r--r--tests/ui/nll/closure-requirements/propagate-fail-to-approximate-longer-wrong-bounds.rs46
-rw-r--r--tests/ui/nll/closure-requirements/propagate-fail-to-approximate-longer-wrong-bounds.stderr35
-rw-r--r--tests/ui/nll/closure-requirements/propagate-from-trait-match.rs48
-rw-r--r--tests/ui/nll/closure-requirements/propagate-from-trait-match.stderr38
-rw-r--r--tests/ui/nll/closure-requirements/propagate-multiple-requirements.rs23
-rw-r--r--tests/ui/nll/closure-requirements/propagate-multiple-requirements.stderr17
-rw-r--r--tests/ui/nll/closure-requirements/region-lbr-anon-does-not-outlive-static.rs13
-rw-r--r--tests/ui/nll/closure-requirements/region-lbr-anon-does-not-outlive-static.stderr10
-rw-r--r--tests/ui/nll/closure-requirements/region-lbr-named-does-not-outlive-static.rs13
-rw-r--r--tests/ui/nll/closure-requirements/region-lbr-named-does-not-outlive-static.stderr10
-rw-r--r--tests/ui/nll/closure-requirements/region-lbr1-does-not-outlive-ebr2.rs13
-rw-r--r--tests/ui/nll/closure-requirements/region-lbr1-does-not-outlive-ebr2.stderr14
-rw-r--r--tests/ui/nll/closure-requirements/region-lbr1-does-outlive-lbr2-because-implied-bound.rs11
-rw-r--r--tests/ui/nll/closure-requirements/return-wrong-bound-region.rs23
-rw-r--r--tests/ui/nll/closure-requirements/return-wrong-bound-region.stderr31
40 files changed, 1387 insertions, 0 deletions
diff --git a/tests/ui/nll/closure-requirements/escape-argument-callee.rs b/tests/ui/nll/closure-requirements/escape-argument-callee.rs
new file mode 100644
index 000000000..3aea511b0
--- /dev/null
+++ b/tests/ui/nll/closure-requirements/escape-argument-callee.rs
@@ -0,0 +1,42 @@
+// Test closure that:
+//
+// - takes an argument `y` with lifetime `'a` (in the code, it's anonymous)
+// - stores `y` into another, longer-lived spot with lifetime `'b`
+//
+// Because `'a` and `'b` are two different, unrelated higher-ranked
+// regions with no relationship to one another, this is an error. This
+// error is reported by the closure itself and is not propagated to
+// its creator: this is because `'a` and `'b` are higher-ranked
+// (late-bound) regions and the closure is not allowed to propagate
+// additional where clauses between higher-ranked regions, only those
+// that appear free in its type (hence, we see it before the closure's
+// "external requirements" report).
+
+// compile-flags:-Zverbose
+
+#![feature(rustc_attrs)]
+
+#[rustc_regions]
+fn test() {
+ let x = 44;
+ let mut p = &x;
+
+ {
+ let y = 22;
+ let mut closure = expect_sig(|p, y| *p = y);
+ //~^ ERROR
+ closure(&mut p, &y);
+ }
+
+ deref(p);
+}
+
+fn expect_sig<F>(f: F) -> F
+ where F: FnMut(&mut &i32, &i32)
+{
+ f
+}
+
+fn deref(_p: &i32) { }
+
+fn main() { }
diff --git a/tests/ui/nll/closure-requirements/escape-argument-callee.stderr b/tests/ui/nll/closure-requirements/escape-argument-callee.stderr
new file mode 100644
index 000000000..363ddfaff
--- /dev/null
+++ b/tests/ui/nll/closure-requirements/escape-argument-callee.stderr
@@ -0,0 +1,31 @@
+note: no external requirements
+ --> $DIR/escape-argument-callee.rs:26:38
+ |
+LL | let mut closure = expect_sig(|p, y| *p = y);
+ | ^^^^^^
+ |
+ = note: defining type: test::{closure#0} with closure substs [
+ i16,
+ for<Region(BrAnon(0, None)), Region(BrAnon(1, None)), Region(BrAnon(2, None))> extern "rust-call" fn((&ReLateBound(DebruijnIndex(0), BoundRegion { var: 0, kind: BrAnon(0, None) }) mut &ReLateBound(DebruijnIndex(0), BoundRegion { var: 1, kind: BrAnon(1, None) }) i32, &ReLateBound(DebruijnIndex(0), BoundRegion { var: 2, kind: BrAnon(2, None) }) i32)),
+ (),
+ ]
+
+error: lifetime may not live long enough
+ --> $DIR/escape-argument-callee.rs:26:45
+ |
+LL | let mut closure = expect_sig(|p, y| *p = y);
+ | - - ^^^^^^ assignment requires that `'1` must outlive `'2`
+ | | |
+ | | has type `&'1 i32`
+ | has type `&'_#2r mut &'2 i32`
+
+note: no external requirements
+ --> $DIR/escape-argument-callee.rs:20:1
+ |
+LL | fn test() {
+ | ^^^^^^^^^
+ |
+ = note: defining type: test
+
+error: aborting due to previous error
+
diff --git a/tests/ui/nll/closure-requirements/escape-argument.rs b/tests/ui/nll/closure-requirements/escape-argument.rs
new file mode 100644
index 000000000..066cd4360
--- /dev/null
+++ b/tests/ui/nll/closure-requirements/escape-argument.rs
@@ -0,0 +1,42 @@
+// Test closure that:
+//
+// - takes an argument `y`
+// - stores `y` into another, longer-lived spot
+//
+// but is invoked with a spot that doesn't live long
+// enough to store `y`.
+//
+// The error is reported in the caller: invoking the closure links the
+// lifetime of the variable that is given as `y` (via subtyping) and
+// thus forces the corresponding borrow to live too long. This is
+// basically checking that the MIR type checker correctly enforces the
+// closure signature.
+
+// compile-flags:-Zverbose
+
+#![feature(rustc_attrs)]
+
+#[rustc_regions]
+fn test() {
+ let x = 44;
+ let mut p = &x;
+
+ {
+ let y = 22;
+ let mut closure = expect_sig(|p, y| *p = y);
+ closure(&mut p, &y);
+ //~^ ERROR `y` does not live long enough [E0597]
+ }
+
+ deref(p);
+}
+
+fn expect_sig<F>(f: F) -> F
+ where F: for<'a, 'b> FnMut(&'a mut &'b i32, &'b i32)
+{
+ f
+}
+
+fn deref(_p: &i32) { }
+
+fn main() { }
diff --git a/tests/ui/nll/closure-requirements/escape-argument.stderr b/tests/ui/nll/closure-requirements/escape-argument.stderr
new file mode 100644
index 000000000..f67c312b9
--- /dev/null
+++ b/tests/ui/nll/closure-requirements/escape-argument.stderr
@@ -0,0 +1,35 @@
+note: no external requirements
+ --> $DIR/escape-argument.rs:26:38
+ |
+LL | let mut closure = expect_sig(|p, y| *p = y);
+ | ^^^^^^
+ |
+ = note: defining type: test::{closure#0} with closure substs [
+ i16,
+ for<Region(BrAnon(0, None)), Region(BrAnon(1, None))> extern "rust-call" fn((&ReLateBound(DebruijnIndex(0), BoundRegion { var: 0, kind: BrAnon(0, None) }) mut &ReLateBound(DebruijnIndex(0), BoundRegion { var: 1, kind: BrAnon(1, None) }) i32, &ReLateBound(DebruijnIndex(0), BoundRegion { var: 1, kind: BrAnon(1, None) }) i32)),
+ (),
+ ]
+
+note: no external requirements
+ --> $DIR/escape-argument.rs:20:1
+ |
+LL | fn test() {
+ | ^^^^^^^^^
+ |
+ = note: defining type: test
+
+error[E0597]: `y` does not live long enough
+ --> $DIR/escape-argument.rs:27:25
+ |
+LL | closure(&mut p, &y);
+ | ^^ borrowed value does not live long enough
+LL |
+LL | }
+ | - `y` dropped here while still borrowed
+LL |
+LL | deref(p);
+ | - borrow later used here
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0597`.
diff --git a/tests/ui/nll/closure-requirements/escape-upvar-nested.rs b/tests/ui/nll/closure-requirements/escape-upvar-nested.rs
new file mode 100644
index 000000000..765a3cf96
--- /dev/null
+++ b/tests/ui/nll/closure-requirements/escape-upvar-nested.rs
@@ -0,0 +1,33 @@
+// As in `escape-upvar-ref.rs`, test closure that:
+//
+// - captures a variable `y`
+// - stores reference to `y` into another, longer-lived spot
+//
+// except that the closure does so via a second closure.
+
+// compile-flags:-Zverbose
+
+#![feature(rustc_attrs)]
+
+#[rustc_regions]
+fn test() {
+ let x = 44;
+ let mut p = &x;
+
+ {
+ let y = 22;
+
+ let mut closure = || {
+ let mut closure1 = || p = &y; //~ ERROR `y` does not live long enough [E0597]
+ closure1();
+ };
+
+ closure();
+ }
+
+ deref(p);
+}
+
+fn deref(_p: &i32) { }
+
+fn main() { }
diff --git a/tests/ui/nll/closure-requirements/escape-upvar-nested.stderr b/tests/ui/nll/closure-requirements/escape-upvar-nested.stderr
new file mode 100644
index 000000000..4fbd5eb19
--- /dev/null
+++ b/tests/ui/nll/closure-requirements/escape-upvar-nested.stderr
@@ -0,0 +1,53 @@
+note: external requirements
+ --> $DIR/escape-upvar-nested.rs:21:32
+ |
+LL | let mut closure1 = || p = &y;
+ | ^^
+ |
+ = note: defining type: test::{closure#0}::{closure#0} with closure substs [
+ i16,
+ extern "rust-call" fn(()),
+ (&'_#1r mut &'_#2r i32, &'_#3r i32),
+ ]
+ = note: number of external vids: 4
+ = note: where '_#3r: '_#2r
+
+note: external requirements
+ --> $DIR/escape-upvar-nested.rs:20:27
+ |
+LL | let mut closure = || {
+ | ^^
+ |
+ = note: defining type: test::{closure#0} with closure substs [
+ i16,
+ extern "rust-call" fn(()),
+ (&'_#1r mut &'_#2r i32, &'_#3r i32),
+ ]
+ = note: number of external vids: 4
+ = note: where '_#3r: '_#2r
+
+note: no external requirements
+ --> $DIR/escape-upvar-nested.rs:13:1
+ |
+LL | fn test() {
+ | ^^^^^^^^^
+ |
+ = note: defining type: test
+
+error[E0597]: `y` does not live long enough
+ --> $DIR/escape-upvar-nested.rs:21:40
+ |
+LL | let mut closure = || {
+ | -- value captured here
+LL | let mut closure1 = || p = &y;
+ | ^ borrowed value does not live long enough
+...
+LL | }
+ | - `y` dropped here while still borrowed
+LL |
+LL | deref(p);
+ | - borrow later used here
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0597`.
diff --git a/tests/ui/nll/closure-requirements/escape-upvar-ref.rs b/tests/ui/nll/closure-requirements/escape-upvar-ref.rs
new file mode 100644
index 000000000..0a562a0a1
--- /dev/null
+++ b/tests/ui/nll/closure-requirements/escape-upvar-ref.rs
@@ -0,0 +1,33 @@
+// Test closure that:
+//
+// - captures a variable `y` by reference
+// - stores that reference to `y` into another, longer-lived place (`p`)
+//
+// Both of these are upvars of reference type (the capture of `y` is
+// of type `&'a i32`, the capture of `p` is of type `&mut &'b
+// i32`). The closure thus computes a relationship between `'a` and
+// `'b`. This relationship is propagated to the closure creator,
+// which reports an error.
+
+// compile-flags:-Zverbose
+
+#![feature(rustc_attrs)]
+
+#[rustc_regions]
+fn test() {
+ let x = 44;
+ let mut p = &x;
+
+ {
+ let y = 22;
+ let mut closure = || p = &y;
+ //~^ ERROR `y` does not live long enough [E0597]
+ closure();
+ }
+
+ deref(p);
+}
+
+fn deref(_p: &i32) { }
+
+fn main() { }
diff --git a/tests/ui/nll/closure-requirements/escape-upvar-ref.stderr b/tests/ui/nll/closure-requirements/escape-upvar-ref.stderr
new file mode 100644
index 000000000..bc1ceac5b
--- /dev/null
+++ b/tests/ui/nll/closure-requirements/escape-upvar-ref.stderr
@@ -0,0 +1,39 @@
+note: external requirements
+ --> $DIR/escape-upvar-ref.rs:23:27
+ |
+LL | let mut closure = || p = &y;
+ | ^^
+ |
+ = note: defining type: test::{closure#0} with closure substs [
+ i16,
+ extern "rust-call" fn(()),
+ (&'_#1r mut &'_#2r i32, &'_#3r i32),
+ ]
+ = note: number of external vids: 4
+ = note: where '_#3r: '_#2r
+
+note: no external requirements
+ --> $DIR/escape-upvar-ref.rs:17:1
+ |
+LL | fn test() {
+ | ^^^^^^^^^
+ |
+ = note: defining type: test
+
+error[E0597]: `y` does not live long enough
+ --> $DIR/escape-upvar-ref.rs:23:35
+ |
+LL | let mut closure = || p = &y;
+ | -- ^ borrowed value does not live long enough
+ | |
+ | value captured here
+...
+LL | }
+ | - `y` dropped here while still borrowed
+LL |
+LL | deref(p);
+ | - borrow later used here
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0597`.
diff --git a/tests/ui/nll/closure-requirements/issue-58127-mutliple-requirements.rs b/tests/ui/nll/closure-requirements/issue-58127-mutliple-requirements.rs
new file mode 100644
index 000000000..a83ebc21f
--- /dev/null
+++ b/tests/ui/nll/closure-requirements/issue-58127-mutliple-requirements.rs
@@ -0,0 +1,36 @@
+// check-pass
+
+// Test that we propagate region relations from closures precisely when there is
+// more than one non-local lower bound.
+
+// In this case the closure has signature
+// |x: &'4 mut (&'5 (&'1 str, &'2 str), &'3 str)| -> ..
+// We end up with a `'3: '5` constraint that we can propagate as
+// `'3: '1`, `'3: '2`, but previously we approximated it as `'3: 'static`.
+
+// As an optimization, we primarily propagate bounds for the "representative"
+// of each SCC. As such we have these two similar cases where hopefully one
+// of them will test the case we want (case2, when this test was added).
+mod case1 {
+ fn f(s: &str) {
+ g(s, |x| h(x));
+ }
+
+ fn g<T, F>(_: T, _: F)
+ where F: Fn(&mut (&(T, T), T)) {}
+
+ fn h<T>(_: &mut (&(T, T), T)) {}
+}
+
+mod case2 {
+ fn f(s: &str) {
+ g(s, |x| h(x));
+ }
+
+ fn g<T, F>(_: T, _: F)
+ where F: Fn(&mut (T, &(T, T))) {}
+
+ fn h<T>(_: &mut (T, &(T, T))) {}
+}
+
+fn main() {}
diff --git a/tests/ui/nll/closure-requirements/propagate-approximated-fail-no-postdom.rs b/tests/ui/nll/closure-requirements/propagate-approximated-fail-no-postdom.rs
new file mode 100644
index 000000000..35a864b88
--- /dev/null
+++ b/tests/ui/nll/closure-requirements/propagate-approximated-fail-no-postdom.rs
@@ -0,0 +1,51 @@
+// Test where we fail to approximate due to demanding a postdom
+// relationship between our upper bounds.
+
+// compile-flags:-Zverbose
+
+#![feature(rustc_attrs)]
+
+use std::cell::Cell;
+
+// Callee knows that:
+//
+// 'x: 'a
+// 'x: 'b
+// 'c: 'y
+//
+// we have to prove that `'x: 'y`. We currently can only approximate
+// via a postdominator -- hence we fail to choose between `'a` and
+// `'b` here and report the error in the closure.
+fn establish_relationships<'a, 'b, 'c, F>(
+ _cell_a: Cell<&'a u32>,
+ _cell_b: Cell<&'b u32>,
+ _cell_c: Cell<&'c u32>,
+ _closure: F,
+) where
+ F: for<'x, 'y> FnMut(
+ Cell<&'a &'x u32>, // shows that 'x: 'a
+ Cell<&'b &'x u32>, // shows that 'x: 'b
+ Cell<&'y &'c u32>, // shows that 'c: 'y
+ Cell<&'x u32>,
+ Cell<&'y u32>,
+ ),
+{
+}
+
+fn demand_y<'x, 'y>(_cell_x: Cell<&'x u32>, _cell_y: Cell<&'y u32>, _y: &'y u32) {}
+
+#[rustc_regions]
+fn supply<'a, 'b, 'c>(cell_a: Cell<&'a u32>, cell_b: Cell<&'b u32>, cell_c: Cell<&'c u32>) {
+ establish_relationships(
+ cell_a,
+ cell_b,
+ cell_c,
+ |_outlives1, _outlives2, _outlives3, x, y| {
+ // Only works if 'x: 'y:
+ let p = x.get();
+ demand_y(x, y, p) //~ ERROR
+ },
+ );
+}
+
+fn main() {}
diff --git a/tests/ui/nll/closure-requirements/propagate-approximated-fail-no-postdom.stderr b/tests/ui/nll/closure-requirements/propagate-approximated-fail-no-postdom.stderr
new file mode 100644
index 000000000..7da6ce58b
--- /dev/null
+++ b/tests/ui/nll/closure-requirements/propagate-approximated-fail-no-postdom.stderr
@@ -0,0 +1,36 @@
+note: no external requirements
+ --> $DIR/propagate-approximated-fail-no-postdom.rs:43:9
+ |
+LL | |_outlives1, _outlives2, _outlives3, x, y| {
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+ = note: defining type: supply::{closure#0} with closure substs [
+ i16,
+ for<Region(BrAnon(0, None)), Region(BrAnon(1, None))> extern "rust-call" fn((std::cell::Cell<&'_#1r &ReLateBound(DebruijnIndex(0), BoundRegion { var: 0, kind: BrAnon(0, None) }) u32>, std::cell::Cell<&'_#2r &ReLateBound(DebruijnIndex(0), BoundRegion { var: 0, kind: BrAnon(0, None) }) u32>, std::cell::Cell<&ReLateBound(DebruijnIndex(0), BoundRegion { var: 1, kind: BrAnon(1, None) }) &'_#3r u32>, std::cell::Cell<&ReLateBound(DebruijnIndex(0), BoundRegion { var: 0, kind: BrAnon(0, None) }) u32>, std::cell::Cell<&ReLateBound(DebruijnIndex(0), BoundRegion { var: 1, kind: BrAnon(1, None) }) u32>)),
+ (),
+ ]
+ = note: late-bound region is '_#4r
+ = note: late-bound region is '_#5r
+ = note: late-bound region is '_#6r
+
+error: lifetime may not live long enough
+ --> $DIR/propagate-approximated-fail-no-postdom.rs:46:13
+ |
+LL | |_outlives1, _outlives2, _outlives3, x, y| {
+ | ---------- ---------- has type `Cell<&'2 &'_#3r u32>`
+ | |
+ | has type `Cell<&'_#1r &'1 u32>`
+...
+LL | demand_y(x, y, p)
+ | ^^^^^^^^^^^^^^^^^ argument requires that `'1` must outlive `'2`
+
+note: no external requirements
+ --> $DIR/propagate-approximated-fail-no-postdom.rs:38:1
+ |
+LL | fn supply<'a, 'b, 'c>(cell_a: Cell<&'a u32>, cell_b: Cell<&'b u32>, cell_c: Cell<&'c u32>) {
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+ = note: defining type: supply
+
+error: aborting due to previous error
+
diff --git a/tests/ui/nll/closure-requirements/propagate-approximated-ref.rs b/tests/ui/nll/closure-requirements/propagate-approximated-ref.rs
new file mode 100644
index 000000000..7291c6e97
--- /dev/null
+++ b/tests/ui/nll/closure-requirements/propagate-approximated-ref.rs
@@ -0,0 +1,50 @@
+// Rather convoluted setup where we infer a relationship between two
+// free regions in the closure signature (`'a` and `'b`) on the basis
+// of a relationship between two bound regions (`'x` and `'y`).
+//
+// The idea is that, thanks to invoking `demand_y`, `'x: 'y` must
+// hold, where `'x` and `'y` are bound regions. The closure can't
+// prove that directly, and because `'x` and `'y` are bound it cannot
+// ask the caller to prove it either. But it has bounds on `'x` and
+// `'y` in terms of `'a` and `'b`, and it can propagate a relationship
+// between `'a` and `'b` to the caller.
+//
+// Note: the use of `Cell` here is to introduce invariance. One less
+// variable.
+
+// compile-flags:-Zverbose
+
+#![feature(rustc_attrs)]
+
+use std::cell::Cell;
+
+// Callee knows that:
+//
+// 'x: 'a
+// 'b: 'y
+//
+// so if we are going to ensure that `'x: 'y`, then `'a: 'b` must
+// hold.
+fn establish_relationships<'a, 'b, F>(_cell_a: &Cell<&'a u32>, _cell_b: &Cell<&'b u32>, _closure: F)
+where
+ F: for<'x, 'y> FnMut(
+ &Cell<&'a &'x u32>, // shows that 'x: 'a
+ &Cell<&'y &'b u32>, // shows that 'b: 'y
+ &Cell<&'x u32>,
+ &Cell<&'y u32>,
+ ),
+{
+}
+
+fn demand_y<'x, 'y>(_cell_x: &Cell<&'x u32>, _cell_y: &Cell<&'y u32>, _y: &'y u32) {}
+
+#[rustc_regions]
+fn supply<'a, 'b>(cell_a: Cell<&'a u32>, cell_b: Cell<&'b u32>) {
+ establish_relationships(&cell_a, &cell_b, |_outlives1, _outlives2, x, y| {
+ // Only works if 'x: 'y:
+ demand_y(x, y, x.get())
+ //~^ ERROR lifetime may not live long enough
+ });
+}
+
+fn main() {}
diff --git a/tests/ui/nll/closure-requirements/propagate-approximated-ref.stderr b/tests/ui/nll/closure-requirements/propagate-approximated-ref.stderr
new file mode 100644
index 000000000..993687605
--- /dev/null
+++ b/tests/ui/nll/closure-requirements/propagate-approximated-ref.stderr
@@ -0,0 +1,39 @@
+note: external requirements
+ --> $DIR/propagate-approximated-ref.rs:43:47
+ |
+LL | establish_relationships(&cell_a, &cell_b, |_outlives1, _outlives2, x, y| {
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+ = note: defining type: supply::{closure#0} with closure substs [
+ i16,
+ for<Region(BrAnon(0, None)), Region(BrAnon(1, None)), Region(BrAnon(2, None)), Region(BrAnon(3, None)), Region(BrAnon(4, None)), Region(BrAnon(5, None))> extern "rust-call" fn((&ReLateBound(DebruijnIndex(0), BoundRegion { var: 0, kind: BrAnon(0, None) }) std::cell::Cell<&'_#1r &ReLateBound(DebruijnIndex(0), BoundRegion { var: 1, kind: BrAnon(1, None) }) u32>, &ReLateBound(DebruijnIndex(0), BoundRegion { var: 2, kind: BrAnon(2, None) }) std::cell::Cell<&ReLateBound(DebruijnIndex(0), BoundRegion { var: 3, kind: BrAnon(3, None) }) &'_#2r u32>, &ReLateBound(DebruijnIndex(0), BoundRegion { var: 4, kind: BrAnon(4, None) }) std::cell::Cell<&ReLateBound(DebruijnIndex(0), BoundRegion { var: 1, kind: BrAnon(1, None) }) u32>, &ReLateBound(DebruijnIndex(0), BoundRegion { var: 5, kind: BrAnon(5, None) }) std::cell::Cell<&ReLateBound(DebruijnIndex(0), BoundRegion { var: 3, kind: BrAnon(3, None) }) u32>)),
+ (),
+ ]
+ = note: late-bound region is '_#3r
+ = note: late-bound region is '_#4r
+ = note: number of external vids: 5
+ = note: where '_#1r: '_#2r
+
+note: no external requirements
+ --> $DIR/propagate-approximated-ref.rs:42:1
+ |
+LL | fn supply<'a, 'b>(cell_a: Cell<&'a u32>, cell_b: Cell<&'b u32>) {
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+ = note: defining type: supply
+
+error: lifetime may not live long enough
+ --> $DIR/propagate-approximated-ref.rs:45:9
+ |
+LL | fn supply<'a, 'b>(cell_a: Cell<&'a u32>, cell_b: Cell<&'b u32>) {
+ | -- -- lifetime `'b` defined here
+ | |
+ | lifetime `'a` defined here
+...
+LL | demand_y(x, y, x.get())
+ | ^^^^^^^^^^^^^^^^^^^^^^^ argument requires that `'a` must outlive `'b`
+ |
+ = help: consider adding the following bound: `'a: 'b`
+
+error: aborting due to previous error
+
diff --git a/tests/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-comparing-against-free.rs b/tests/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-comparing-against-free.rs
new file mode 100644
index 000000000..afe6f10a5
--- /dev/null
+++ b/tests/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-comparing-against-free.rs
@@ -0,0 +1,40 @@
+// Test a case where we setup relationships like `'x: 'a` or `'a: 'x`,
+// where `'x` is bound in closure type but `'a` is free. This forces
+// us to approximate `'x` one way or the other.
+
+// compile-flags:-Zverbose
+
+#![feature(rustc_attrs)]
+
+use std::cell::Cell;
+
+fn foo<'a, F>(_cell: Cell<&'a u32>, _f: F)
+where
+ F: for<'x> FnOnce(Cell<&'a u32>, Cell<&'x u32>),
+{
+}
+
+#[rustc_regions]
+fn case1() {
+ let a = 0;
+ let cell = Cell::new(&a);
+ foo(cell, |cell_a, cell_x| {
+ cell_a.set(cell_x.get()); // forces 'x: 'a, error in closure
+ //~^ ERROR
+ })
+}
+
+#[rustc_regions]
+fn case2() {
+ let a = 0;
+ let cell = Cell::new(&a);
+ //~^ ERROR `a` does not live long enough
+
+ // As you can see in the stderr output, this closure propoagates a
+ // requirement that `'a: 'static'.
+ foo(cell, |cell_a, cell_x| {
+ cell_x.set(cell_a.get()); // forces 'a: 'x, implies 'a = 'static -> borrow error
+ })
+}
+
+fn main() { }
diff --git a/tests/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-comparing-against-free.stderr b/tests/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-comparing-against-free.stderr
new file mode 100644
index 000000000..7991abeb7
--- /dev/null
+++ b/tests/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-comparing-against-free.stderr
@@ -0,0 +1,69 @@
+note: no external requirements
+ --> $DIR/propagate-approximated-shorter-to-static-comparing-against-free.rs:21:15
+ |
+LL | foo(cell, |cell_a, cell_x| {
+ | ^^^^^^^^^^^^^^^^
+ |
+ = note: defining type: case1::{closure#0} with closure substs [
+ i32,
+ for<Region(BrAnon(0, None))> extern "rust-call" fn((std::cell::Cell<&'_#1r u32>, std::cell::Cell<&ReLateBound(DebruijnIndex(0), BoundRegion { var: 0, kind: BrAnon(0, None) }) u32>)),
+ (),
+ ]
+
+error[E0521]: borrowed data escapes outside of closure
+ --> $DIR/propagate-approximated-shorter-to-static-comparing-against-free.rs:22:9
+ |
+LL | foo(cell, |cell_a, cell_x| {
+ | ------ ------ `cell_x` is a reference that is only valid in the closure body
+ | |
+ | `cell_a` declared here, outside of the closure body
+LL | cell_a.set(cell_x.get()); // forces 'x: 'a, error in closure
+ | ^^^^^^^^^^^^^^^^^^^^^^^^ `cell_x` escapes the closure body here
+
+note: no external requirements
+ --> $DIR/propagate-approximated-shorter-to-static-comparing-against-free.rs:18:1
+ |
+LL | fn case1() {
+ | ^^^^^^^^^^
+ |
+ = note: defining type: case1
+
+note: external requirements
+ --> $DIR/propagate-approximated-shorter-to-static-comparing-against-free.rs:35:15
+ |
+LL | foo(cell, |cell_a, cell_x| {
+ | ^^^^^^^^^^^^^^^^
+ |
+ = note: defining type: case2::{closure#0} with closure substs [
+ i32,
+ for<Region(BrAnon(0, None))> extern "rust-call" fn((std::cell::Cell<&'_#1r u32>, std::cell::Cell<&ReLateBound(DebruijnIndex(0), BoundRegion { var: 0, kind: BrAnon(0, None) }) u32>)),
+ (),
+ ]
+ = note: number of external vids: 2
+ = note: where '_#1r: '_#0r
+
+note: no external requirements
+ --> $DIR/propagate-approximated-shorter-to-static-comparing-against-free.rs:28:1
+ |
+LL | fn case2() {
+ | ^^^^^^^^^^
+ |
+ = note: defining type: case2
+
+error[E0597]: `a` does not live long enough
+ --> $DIR/propagate-approximated-shorter-to-static-comparing-against-free.rs:30:26
+ |
+LL | let cell = Cell::new(&a);
+ | ^^ borrowed value does not live long enough
+...
+LL | / foo(cell, |cell_a, cell_x| {
+LL | | cell_x.set(cell_a.get()); // forces 'a: 'x, implies 'a = 'static -> borrow error
+LL | | })
+ | |______- argument requires that `a` is borrowed for `'static`
+LL | }
+ | - `a` dropped here while still borrowed
+
+error: aborting due to 2 previous errors
+
+Some errors have detailed explanations: E0521, E0597.
+For more information about an error, try `rustc --explain E0521`.
diff --git a/tests/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-no-bound.rs b/tests/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-no-bound.rs
new file mode 100644
index 000000000..372209075
--- /dev/null
+++ b/tests/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-no-bound.rs
@@ -0,0 +1,40 @@
+// Test a case where we are trying to prove `'x: 'y` and are forced to
+// approximate the shorter end-point (`'y`) to with `'static`. This is
+// because `'y` is higher-ranked but we know of no relations to other
+// regions. Note that `'static` shows up in the stderr output as `'0`.
+
+// compile-flags:-Zverbose
+
+#![feature(rustc_attrs)]
+
+use std::cell::Cell;
+
+// Callee knows that:
+//
+// 'x: 'a
+//
+// so the only way we can ensure that `'x: 'y` is to show that
+// `'a: 'static`.
+fn establish_relationships<'a, 'b, F>(_cell_a: &Cell<&'a u32>, _cell_b: &Cell<&'b u32>, _closure: F)
+where
+ F: for<'x, 'y> FnMut(
+ &Cell<&'a &'x u32>, // shows that 'x: 'a
+ &Cell<&'x u32>,
+ &Cell<&'y u32>,
+ ),
+{
+}
+
+fn demand_y<'x, 'y>(_cell_x: &Cell<&'x u32>, _cell_y: &Cell<&'y u32>, _y: &'y u32) {}
+
+#[rustc_regions]
+fn supply<'a, 'b>(cell_a: Cell<&'a u32>, cell_b: Cell<&'b u32>) {
+ establish_relationships(&cell_a, &cell_b, |_outlives, x, y| {
+ //~^ ERROR borrowed data escapes outside of function
+
+ // Only works if 'x: 'y:
+ demand_y(x, y, x.get())
+ });
+}
+
+fn main() {}
diff --git a/tests/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-no-bound.stderr b/tests/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-no-bound.stderr
new file mode 100644
index 000000000..43dfc3bb9
--- /dev/null
+++ b/tests/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-no-bound.stderr
@@ -0,0 +1,49 @@
+note: external requirements
+ --> $DIR/propagate-approximated-shorter-to-static-no-bound.rs:32:47
+ |
+LL | establish_relationships(&cell_a, &cell_b, |_outlives, x, y| {
+ | ^^^^^^^^^^^^^^^^^
+ |
+ = note: defining type: supply::{closure#0} with closure substs [
+ i16,
+ for<Region(BrAnon(0, None)), Region(BrAnon(1, None)), Region(BrAnon(2, None)), Region(BrAnon(3, None)), Region(BrAnon(4, None))> extern "rust-call" fn((&ReLateBound(DebruijnIndex(0), BoundRegion { var: 0, kind: BrAnon(0, None) }) std::cell::Cell<&'_#1r &ReLateBound(DebruijnIndex(0), BoundRegion { var: 1, kind: BrAnon(1, None) }) u32>, &ReLateBound(DebruijnIndex(0), BoundRegion { var: 2, kind: BrAnon(2, None) }) std::cell::Cell<&ReLateBound(DebruijnIndex(0), BoundRegion { var: 1, kind: BrAnon(1, None) }) u32>, &ReLateBound(DebruijnIndex(0), BoundRegion { var: 3, kind: BrAnon(3, None) }) std::cell::Cell<&ReLateBound(DebruijnIndex(0), BoundRegion { var: 4, kind: BrAnon(4, None) }) u32>)),
+ (),
+ ]
+ = note: late-bound region is '_#2r
+ = note: late-bound region is '_#3r
+ = note: number of external vids: 4
+ = note: where '_#1r: '_#0r
+
+note: no external requirements
+ --> $DIR/propagate-approximated-shorter-to-static-no-bound.rs:31:1
+ |
+LL | fn supply<'a, 'b>(cell_a: Cell<&'a u32>, cell_b: Cell<&'b u32>) {
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+ = note: defining type: supply
+
+error[E0521]: borrowed data escapes outside of function
+ --> $DIR/propagate-approximated-shorter-to-static-no-bound.rs:32:5
+ |
+LL | fn supply<'a, 'b>(cell_a: Cell<&'a u32>, cell_b: Cell<&'b u32>) {
+ | -- ------ `cell_a` is a reference that is only valid in the function body
+ | |
+ | lifetime `'a` defined here
+LL | / establish_relationships(&cell_a, &cell_b, |_outlives, x, y| {
+LL | |
+LL | |
+LL | | // Only works if 'x: 'y:
+LL | | demand_y(x, y, x.get())
+LL | | });
+ | | ^
+ | | |
+ | |______`cell_a` escapes the function body here
+ | argument requires that `'a` must outlive `'static`
+ |
+ = note: requirement occurs because of the type `Cell<&'_#9r u32>`, which makes the generic argument `&'_#9r u32` invariant
+ = note: the struct `Cell<T>` is invariant over the parameter `T`
+ = help: see <https://doc.rust-lang.org/nomicon/subtyping.html> for more information about variance
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0521`.
diff --git a/tests/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-wrong-bound.rs b/tests/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-wrong-bound.rs
new file mode 100644
index 000000000..9898777c7
--- /dev/null
+++ b/tests/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-wrong-bound.rs
@@ -0,0 +1,43 @@
+// Test a case where we are trying to prove `'x: 'y` and are forced to
+// approximate the shorter end-point (`'y`) to with `'static`. This is
+// because `'y` is higher-ranked but we know of only irrelevant
+// relations to other regions. Note that `'static` shows up in the
+// stderr output as `'0`.
+
+// compile-flags:-Zverbose
+
+#![feature(rustc_attrs)]
+
+use std::cell::Cell;
+
+// Callee knows that:
+//
+// 'x: 'a
+// 'y: 'b
+//
+// so the only way we can ensure that `'x: 'y` is to show that
+// `'a: 'static`.
+fn establish_relationships<'a, 'b, F>(_cell_a: &Cell<&'a u32>, _cell_b: &Cell<&'b u32>, _closure: F)
+where
+ F: for<'x, 'y> FnMut(
+ &Cell<&'a &'x u32>, // shows that 'x: 'a
+ &Cell<&'b &'y u32>, // shows that 'y: 'b
+ &Cell<&'x u32>,
+ &Cell<&'y u32>,
+ ),
+{
+}
+
+fn demand_y<'x, 'y>(_cell_x: &Cell<&'x u32>, _cell_y: &Cell<&'y u32>, _y: &'y u32) {}
+
+#[rustc_regions]
+fn supply<'a, 'b>(cell_a: Cell<&'a u32>, cell_b: Cell<&'b u32>) {
+ establish_relationships(&cell_a, &cell_b, |_outlives1, _outlives2, x, y| {
+ //~^ ERROR borrowed data escapes outside of function
+
+ // Only works if 'x: 'y:
+ demand_y(x, y, x.get())
+ });
+}
+
+fn main() {}
diff --git a/tests/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-wrong-bound.stderr b/tests/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-wrong-bound.stderr
new file mode 100644
index 000000000..96c734226
--- /dev/null
+++ b/tests/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-wrong-bound.stderr
@@ -0,0 +1,49 @@
+note: external requirements
+ --> $DIR/propagate-approximated-shorter-to-static-wrong-bound.rs:35:47
+ |
+LL | establish_relationships(&cell_a, &cell_b, |_outlives1, _outlives2, x, y| {
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+ = note: defining type: supply::{closure#0} with closure substs [
+ i16,
+ for<Region(BrAnon(0, None)), Region(BrAnon(1, None)), Region(BrAnon(2, None)), Region(BrAnon(3, None)), Region(BrAnon(4, None)), Region(BrAnon(5, None))> extern "rust-call" fn((&ReLateBound(DebruijnIndex(0), BoundRegion { var: 0, kind: BrAnon(0, None) }) std::cell::Cell<&'_#1r &ReLateBound(DebruijnIndex(0), BoundRegion { var: 1, kind: BrAnon(1, None) }) u32>, &ReLateBound(DebruijnIndex(0), BoundRegion { var: 2, kind: BrAnon(2, None) }) std::cell::Cell<&'_#2r &ReLateBound(DebruijnIndex(0), BoundRegion { var: 3, kind: BrAnon(3, None) }) u32>, &ReLateBound(DebruijnIndex(0), BoundRegion { var: 4, kind: BrAnon(4, None) }) std::cell::Cell<&ReLateBound(DebruijnIndex(0), BoundRegion { var: 1, kind: BrAnon(1, None) }) u32>, &ReLateBound(DebruijnIndex(0), BoundRegion { var: 5, kind: BrAnon(5, None) }) std::cell::Cell<&ReLateBound(DebruijnIndex(0), BoundRegion { var: 3, kind: BrAnon(3, None) }) u32>)),
+ (),
+ ]
+ = note: late-bound region is '_#3r
+ = note: late-bound region is '_#4r
+ = note: number of external vids: 5
+ = note: where '_#1r: '_#0r
+
+note: no external requirements
+ --> $DIR/propagate-approximated-shorter-to-static-wrong-bound.rs:34:1
+ |
+LL | fn supply<'a, 'b>(cell_a: Cell<&'a u32>, cell_b: Cell<&'b u32>) {
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+ = note: defining type: supply
+
+error[E0521]: borrowed data escapes outside of function
+ --> $DIR/propagate-approximated-shorter-to-static-wrong-bound.rs:35:5
+ |
+LL | fn supply<'a, 'b>(cell_a: Cell<&'a u32>, cell_b: Cell<&'b u32>) {
+ | -- ------ `cell_a` is a reference that is only valid in the function body
+ | |
+ | lifetime `'a` defined here
+LL | / establish_relationships(&cell_a, &cell_b, |_outlives1, _outlives2, x, y| {
+LL | |
+LL | |
+LL | | // Only works if 'x: 'y:
+LL | | demand_y(x, y, x.get())
+LL | | });
+ | | ^
+ | | |
+ | |______`cell_a` escapes the function body here
+ | argument requires that `'a` must outlive `'static`
+ |
+ = note: requirement occurs because of the type `Cell<&'_#10r u32>`, which makes the generic argument `&'_#10r u32` invariant
+ = note: the struct `Cell<T>` is invariant over the parameter `T`
+ = help: see <https://doc.rust-lang.org/nomicon/subtyping.html> for more information about variance
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0521`.
diff --git a/tests/ui/nll/closure-requirements/propagate-approximated-val.rs b/tests/ui/nll/closure-requirements/propagate-approximated-val.rs
new file mode 100644
index 000000000..5bb5eea99
--- /dev/null
+++ b/tests/ui/nll/closure-requirements/propagate-approximated-val.rs
@@ -0,0 +1,43 @@
+// A simpler variant of `outlives-from-argument` where cells are
+// passed by value.
+//
+// This is simpler because there are no "extraneous" region
+// relationships. In the 'main' variant, there are a number of
+// anonymous regions as well.
+
+// compile-flags:-Zverbose
+
+#![feature(rustc_attrs)]
+
+use std::cell::Cell;
+
+// Callee knows that:
+//
+// 'x: 'a
+// 'b: 'y
+//
+// so if we are going to ensure that `'x: 'y`, then `'a: 'b` must
+// hold.
+fn establish_relationships<'a, 'b, F>(_cell_a: Cell<&'a u32>, _cell_b: Cell<&'b u32>, _closure: F)
+where
+ F: for<'x, 'y> FnMut(
+ Cell<&'a &'x u32>, // shows that 'x: 'a
+ Cell<&'y &'b u32>, // shows that 'b: 'y
+ Cell<&'x u32>,
+ Cell<&'y u32>,
+ ),
+{
+}
+
+fn demand_y<'x, 'y>(_outlives1: Cell<&&'x u32>, _outlives2: Cell<&'y &u32>, _y: &'y u32) {}
+
+#[rustc_regions]
+fn test<'a, 'b>(cell_a: Cell<&'a u32>, cell_b: Cell<&'b u32>) {
+ establish_relationships(cell_a, cell_b, |outlives1, outlives2, x, y| {
+ // Only works if 'x: 'y:
+ demand_y(outlives1, outlives2, x.get())
+ //~^ ERROR lifetime may not live long enough
+ });
+}
+
+fn main() {}
diff --git a/tests/ui/nll/closure-requirements/propagate-approximated-val.stderr b/tests/ui/nll/closure-requirements/propagate-approximated-val.stderr
new file mode 100644
index 000000000..03dbd686e
--- /dev/null
+++ b/tests/ui/nll/closure-requirements/propagate-approximated-val.stderr
@@ -0,0 +1,39 @@
+note: external requirements
+ --> $DIR/propagate-approximated-val.rs:36:45
+ |
+LL | establish_relationships(cell_a, cell_b, |outlives1, outlives2, x, y| {
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+ = note: defining type: test::{closure#0} with closure substs [
+ i16,
+ for<Region(BrAnon(0, None)), Region(BrAnon(1, None))> extern "rust-call" fn((std::cell::Cell<&'_#1r &ReLateBound(DebruijnIndex(0), BoundRegion { var: 0, kind: BrAnon(0, None) }) u32>, std::cell::Cell<&ReLateBound(DebruijnIndex(0), BoundRegion { var: 1, kind: BrAnon(1, None) }) &'_#2r u32>, std::cell::Cell<&ReLateBound(DebruijnIndex(0), BoundRegion { var: 0, kind: BrAnon(0, None) }) u32>, std::cell::Cell<&ReLateBound(DebruijnIndex(0), BoundRegion { var: 1, kind: BrAnon(1, None) }) u32>)),
+ (),
+ ]
+ = note: late-bound region is '_#3r
+ = note: late-bound region is '_#4r
+ = note: number of external vids: 5
+ = note: where '_#1r: '_#2r
+
+note: no external requirements
+ --> $DIR/propagate-approximated-val.rs:35:1
+ |
+LL | fn test<'a, 'b>(cell_a: Cell<&'a u32>, cell_b: Cell<&'b u32>) {
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+ = note: defining type: test
+
+error: lifetime may not live long enough
+ --> $DIR/propagate-approximated-val.rs:38:9
+ |
+LL | fn test<'a, 'b>(cell_a: Cell<&'a u32>, cell_b: Cell<&'b u32>) {
+ | -- -- lifetime `'b` defined here
+ | |
+ | lifetime `'a` defined here
+...
+LL | demand_y(outlives1, outlives2, x.get())
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ argument requires that `'a` must outlive `'b`
+ |
+ = help: consider adding the following bound: `'a: 'b`
+
+error: aborting due to previous error
+
diff --git a/tests/ui/nll/closure-requirements/propagate-despite-same-free-region.rs b/tests/ui/nll/closure-requirements/propagate-despite-same-free-region.rs
new file mode 100644
index 000000000..704a026d2
--- /dev/null
+++ b/tests/ui/nll/closure-requirements/propagate-despite-same-free-region.rs
@@ -0,0 +1,50 @@
+// Test where we might in theory be able to see that the relationship
+// between two bound regions is true within closure and hence have no
+// need to propagate; but in fact we do because identity of free
+// regions is erased.
+
+// compile-flags:-Zverbose
+// check-pass
+
+#![feature(rustc_attrs)]
+
+use std::cell::Cell;
+
+// In theory, callee knows that:
+//
+// 'x: 'a
+// 'a: 'y
+//
+// and hence could satisfy that `'x: 'y` locally. However, in our
+// checking, we ignore the precise free regions that come into the
+// region and just assign each position a distinct universally bound
+// region. Hence, we propagate a constraint to our caller that will
+// wind up being solvable.
+fn establish_relationships<'a, F>(
+ _cell_a: Cell<&'a u32>,
+ _closure: F,
+) where
+ F: for<'x, 'y> FnMut(
+ Cell<&'a &'x u32>, // shows that 'x: 'a
+ Cell<&'y &'a u32>, // shows that 'a: 'y
+ Cell<&'x u32>,
+ Cell<&'y u32>,
+ ),
+{
+}
+
+fn demand_y<'x, 'y>(_cell_x: Cell<&'x u32>, _cell_y: Cell<&'y u32>, _y: &'y u32) {}
+
+#[rustc_regions]
+fn supply<'a>(cell_a: Cell<&'a u32>) {
+ establish_relationships(
+ cell_a,
+ |_outlives1, _outlives2, x, y| {
+ // Only works if 'x: 'y:
+ let p = x.get();
+ demand_y(x, y, p)
+ },
+ );
+}
+
+fn main() {}
diff --git a/tests/ui/nll/closure-requirements/propagate-despite-same-free-region.stderr b/tests/ui/nll/closure-requirements/propagate-despite-same-free-region.stderr
new file mode 100644
index 000000000..d716d3de2
--- /dev/null
+++ b/tests/ui/nll/closure-requirements/propagate-despite-same-free-region.stderr
@@ -0,0 +1,23 @@
+note: external requirements
+ --> $DIR/propagate-despite-same-free-region.rs:42:9
+ |
+LL | |_outlives1, _outlives2, x, y| {
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+ = note: defining type: supply::{closure#0} with closure substs [
+ i16,
+ for<Region(BrAnon(0, None)), Region(BrAnon(1, None))> extern "rust-call" fn((std::cell::Cell<&'_#1r &ReLateBound(DebruijnIndex(0), BoundRegion { var: 0, kind: BrAnon(0, None) }) u32>, std::cell::Cell<&ReLateBound(DebruijnIndex(0), BoundRegion { var: 1, kind: BrAnon(1, None) }) &'_#2r u32>, std::cell::Cell<&ReLateBound(DebruijnIndex(0), BoundRegion { var: 0, kind: BrAnon(0, None) }) u32>, std::cell::Cell<&ReLateBound(DebruijnIndex(0), BoundRegion { var: 1, kind: BrAnon(1, None) }) u32>)),
+ (),
+ ]
+ = note: late-bound region is '_#3r
+ = note: number of external vids: 4
+ = note: where '_#1r: '_#2r
+
+note: no external requirements
+ --> $DIR/propagate-despite-same-free-region.rs:39:1
+ |
+LL | fn supply<'a>(cell_a: Cell<&'a u32>) {
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+ = note: defining type: supply
+
diff --git a/tests/ui/nll/closure-requirements/propagate-fail-to-approximate-longer-no-bounds.rs b/tests/ui/nll/closure-requirements/propagate-fail-to-approximate-longer-no-bounds.rs
new file mode 100644
index 000000000..dcd05d7fa
--- /dev/null
+++ b/tests/ui/nll/closure-requirements/propagate-fail-to-approximate-longer-no-bounds.rs
@@ -0,0 +1,42 @@
+// Similarly to escape-argument-callee, a test case where the closure
+// requires a relationship between 2 unrelated higher-ranked regions,
+// with no helpful relations between the HRRs and free regions.
+//
+// In this case, the error is reported by the closure itself. This is
+// because it is unable to approximate the higher-ranked region `'x`,
+// as it knows of no relationships between `'x` and any
+// non-higher-ranked regions.
+
+// compile-flags:-Zverbose
+
+#![feature(rustc_attrs)]
+
+use std::cell::Cell;
+
+// Callee knows that:
+//
+// 'b: 'y
+//
+// but this doesn't really help us in proving that `'x: 'y`, so closure gets an error.
+fn establish_relationships<'a, 'b, F>(_cell_a: &Cell<&'a u32>, _cell_b: &Cell<&'b u32>, _closure: F)
+where
+ F: for<'x, 'y> FnMut(
+ &Cell<&'y &'b u32>, // shows that 'b: 'y
+ &Cell<&'x u32>,
+ &Cell<&'y u32>,
+ ),
+{
+}
+
+fn demand_y<'x, 'y>(_cell_x: &Cell<&'x u32>, _cell_y: &Cell<&'y u32>, _y: &'y u32) {}
+
+#[rustc_regions]
+fn supply<'a, 'b>(cell_a: Cell<&'a u32>, cell_b: Cell<&'b u32>) {
+ establish_relationships(&cell_a, &cell_b, |_outlives, x, y| {
+ // Only works if 'x: 'y:
+ demand_y(x, y, x.get())
+ //~^ ERROR
+ });
+}
+
+fn main() {}
diff --git a/tests/ui/nll/closure-requirements/propagate-fail-to-approximate-longer-no-bounds.stderr b/tests/ui/nll/closure-requirements/propagate-fail-to-approximate-longer-no-bounds.stderr
new file mode 100644
index 000000000..b924873fc
--- /dev/null
+++ b/tests/ui/nll/closure-requirements/propagate-fail-to-approximate-longer-no-bounds.stderr
@@ -0,0 +1,35 @@
+note: no external requirements
+ --> $DIR/propagate-fail-to-approximate-longer-no-bounds.rs:35:47
+ |
+LL | establish_relationships(&cell_a, &cell_b, |_outlives, x, y| {
+ | ^^^^^^^^^^^^^^^^^
+ |
+ = note: defining type: supply::{closure#0} with closure substs [
+ i16,
+ for<Region(BrAnon(0, None)), Region(BrAnon(1, None)), Region(BrAnon(2, None)), Region(BrAnon(3, None)), Region(BrAnon(4, None))> extern "rust-call" fn((&ReLateBound(DebruijnIndex(0), BoundRegion { var: 0, kind: BrAnon(0, None) }) std::cell::Cell<&ReLateBound(DebruijnIndex(0), BoundRegion { var: 1, kind: BrAnon(1, None) }) &'_#1r u32>, &ReLateBound(DebruijnIndex(0), BoundRegion { var: 2, kind: BrAnon(2, None) }) std::cell::Cell<&ReLateBound(DebruijnIndex(0), BoundRegion { var: 3, kind: BrAnon(3, None) }) u32>, &ReLateBound(DebruijnIndex(0), BoundRegion { var: 4, kind: BrAnon(4, None) }) std::cell::Cell<&ReLateBound(DebruijnIndex(0), BoundRegion { var: 1, kind: BrAnon(1, None) }) u32>)),
+ (),
+ ]
+ = note: late-bound region is '_#2r
+ = note: late-bound region is '_#3r
+
+error: lifetime may not live long enough
+ --> $DIR/propagate-fail-to-approximate-longer-no-bounds.rs:37:9
+ |
+LL | establish_relationships(&cell_a, &cell_b, |_outlives, x, y| {
+ | --------- - has type `&'_#7r Cell<&'1 u32>`
+ | |
+ | has type `&'_#5r Cell<&'2 &'_#1r u32>`
+LL | // Only works if 'x: 'y:
+LL | demand_y(x, y, x.get())
+ | ^^^^^^^^^^^^^^^^^^^^^^^ argument requires that `'1` must outlive `'2`
+
+note: no external requirements
+ --> $DIR/propagate-fail-to-approximate-longer-no-bounds.rs:34:1
+ |
+LL | fn supply<'a, 'b>(cell_a: Cell<&'a u32>, cell_b: Cell<&'b u32>) {
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+ = note: defining type: supply
+
+error: aborting due to previous error
+
diff --git a/tests/ui/nll/closure-requirements/propagate-fail-to-approximate-longer-wrong-bounds.rs b/tests/ui/nll/closure-requirements/propagate-fail-to-approximate-longer-wrong-bounds.rs
new file mode 100644
index 000000000..98be92d1c
--- /dev/null
+++ b/tests/ui/nll/closure-requirements/propagate-fail-to-approximate-longer-wrong-bounds.rs
@@ -0,0 +1,46 @@
+// Similarly to escape-argument-callee, a test case where the closure
+// requires a relationship between 2 unrelated higher-ranked regions,
+// with no helpful relations between the HRRs and free regions.
+//
+// In this case, the error is reported by the closure itself. This is
+// because it is unable to approximate the higher-ranked region `'x`,
+// as it only knows of regions that `'x` is outlived by, and none that
+// `'x` outlives.
+
+// compile-flags:-Zverbose
+
+#![feature(rustc_attrs)]
+
+use std::cell::Cell;
+
+// Callee knows that:
+//
+// 'a: 'x
+// 'b: 'y
+//
+// but this doesn't really help us in proving that `'x: 'y`, so
+// closure gets an error. In particular, we would need to know that
+// `'x: 'a`, so that we could approximate `'x` "downwards" to `'a`.
+fn establish_relationships<'a, 'b, F>(_cell_a: &Cell<&'a u32>, _cell_b: &Cell<&'b u32>, _closure: F)
+where
+ F: for<'x, 'y> FnMut(
+ &Cell<&'x &'a u32>, // shows that 'a: 'x
+ &Cell<&'y &'b u32>, // shows that 'b: 'y
+ &Cell<&'x u32>,
+ &Cell<&'y u32>,
+ ),
+{
+}
+
+fn demand_y<'x, 'y>(_cell_x: &Cell<&'x u32>, _cell_y: &Cell<&'y u32>, _y: &'y u32) {}
+
+#[rustc_regions]
+fn supply<'a, 'b>(cell_a: Cell<&'a u32>, cell_b: Cell<&'b u32>) {
+ establish_relationships(&cell_a, &cell_b, |_outlives1, _outlives2, x, y| {
+ // Only works if 'x: 'y:
+ demand_y(x, y, x.get())
+ //~^ ERROR
+ });
+}
+
+fn main() {}
diff --git a/tests/ui/nll/closure-requirements/propagate-fail-to-approximate-longer-wrong-bounds.stderr b/tests/ui/nll/closure-requirements/propagate-fail-to-approximate-longer-wrong-bounds.stderr
new file mode 100644
index 000000000..9b25efd0b
--- /dev/null
+++ b/tests/ui/nll/closure-requirements/propagate-fail-to-approximate-longer-wrong-bounds.stderr
@@ -0,0 +1,35 @@
+note: no external requirements
+ --> $DIR/propagate-fail-to-approximate-longer-wrong-bounds.rs:39:47
+ |
+LL | establish_relationships(&cell_a, &cell_b, |_outlives1, _outlives2, x, y| {
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+ = note: defining type: supply::{closure#0} with closure substs [
+ i16,
+ for<Region(BrAnon(0, None)), Region(BrAnon(1, None)), Region(BrAnon(2, None)), Region(BrAnon(3, None)), Region(BrAnon(4, None)), Region(BrAnon(5, None))> extern "rust-call" fn((&ReLateBound(DebruijnIndex(0), BoundRegion { var: 0, kind: BrAnon(0, None) }) std::cell::Cell<&ReLateBound(DebruijnIndex(0), BoundRegion { var: 1, kind: BrAnon(1, None) }) &'_#1r u32>, &ReLateBound(DebruijnIndex(0), BoundRegion { var: 2, kind: BrAnon(2, None) }) std::cell::Cell<&ReLateBound(DebruijnIndex(0), BoundRegion { var: 3, kind: BrAnon(3, None) }) &'_#2r u32>, &ReLateBound(DebruijnIndex(0), BoundRegion { var: 4, kind: BrAnon(4, None) }) std::cell::Cell<&ReLateBound(DebruijnIndex(0), BoundRegion { var: 1, kind: BrAnon(1, None) }) u32>, &ReLateBound(DebruijnIndex(0), BoundRegion { var: 5, kind: BrAnon(5, None) }) std::cell::Cell<&ReLateBound(DebruijnIndex(0), BoundRegion { var: 3, kind: BrAnon(3, None) }) u32>)),
+ (),
+ ]
+ = note: late-bound region is '_#3r
+ = note: late-bound region is '_#4r
+
+error: lifetime may not live long enough
+ --> $DIR/propagate-fail-to-approximate-longer-wrong-bounds.rs:41:9
+ |
+LL | establish_relationships(&cell_a, &cell_b, |_outlives1, _outlives2, x, y| {
+ | ---------- ---------- has type `&'_#8r Cell<&'2 &'_#2r u32>`
+ | |
+ | has type `&'_#6r Cell<&'1 &'_#1r u32>`
+LL | // Only works if 'x: 'y:
+LL | demand_y(x, y, x.get())
+ | ^^^^^^^^^^^^^^^^^^^^^^^ argument requires that `'1` must outlive `'2`
+
+note: no external requirements
+ --> $DIR/propagate-fail-to-approximate-longer-wrong-bounds.rs:38:1
+ |
+LL | fn supply<'a, 'b>(cell_a: Cell<&'a u32>, cell_b: Cell<&'b u32>) {
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+ = note: defining type: supply
+
+error: aborting due to previous error
+
diff --git a/tests/ui/nll/closure-requirements/propagate-from-trait-match.rs b/tests/ui/nll/closure-requirements/propagate-from-trait-match.rs
new file mode 100644
index 000000000..cda781d8e
--- /dev/null
+++ b/tests/ui/nll/closure-requirements/propagate-from-trait-match.rs
@@ -0,0 +1,48 @@
+// Test that regions which appear only in the closure's generics (in
+// this case, `'a`) are properly mapped to the creator's generics. In
+// this case, the closure constrains its type parameter `T` to outlive
+// the same `'a` for which it implements `Trait`, which can only be the `'a`
+// from the function definition.
+
+// compile-flags:-Zverbose
+
+#![feature(rustc_attrs)]
+#![allow(dead_code)]
+
+trait Trait<'a> {}
+
+fn establish_relationships<T, F>(value: T, closure: F)
+where
+ F: FnOnce(T),
+{
+ closure(value)
+}
+
+fn require<'a, T>(t: T)
+where
+ T: Trait<'a> + 'a,
+{
+}
+
+#[rustc_regions]
+fn supply<'a, T>(value: T)
+where
+ T: Trait<'a>,
+{
+ establish_relationships(value, |value| {
+ // This function call requires that
+ //
+ // (a) T: Trait<'a>
+ //
+ // and
+ //
+ // (b) T: 'a
+ //
+ // The latter does not hold.
+
+ require(value);
+ //~^ ERROR the parameter type `T` may not live long enough
+ });
+}
+
+fn main() {}
diff --git a/tests/ui/nll/closure-requirements/propagate-from-trait-match.stderr b/tests/ui/nll/closure-requirements/propagate-from-trait-match.stderr
new file mode 100644
index 000000000..038a5e11f
--- /dev/null
+++ b/tests/ui/nll/closure-requirements/propagate-from-trait-match.stderr
@@ -0,0 +1,38 @@
+note: external requirements
+ --> $DIR/propagate-from-trait-match.rs:32:36
+ |
+LL | establish_relationships(value, |value| {
+ | ^^^^^^^
+ |
+ = note: defining type: supply::<'_#1r, T>::{closure#0} with closure substs [
+ i32,
+ extern "rust-call" fn((T,)),
+ (),
+ ]
+ = note: number of external vids: 2
+ = note: where T: '_#1r
+
+note: no external requirements
+ --> $DIR/propagate-from-trait-match.rs:28:1
+ |
+LL | / fn supply<'a, T>(value: T)
+LL | | where
+LL | | T: Trait<'a>,
+ | |_________________^
+ |
+ = note: defining type: supply::<'_#1r, T>
+
+error[E0309]: the parameter type `T` may not live long enough
+ --> $DIR/propagate-from-trait-match.rs:43:9
+ |
+LL | require(value);
+ | ^^^^^^^^^^^^^^ ...so that the type `T` will meet its required lifetime bounds
+ |
+help: consider adding an explicit lifetime bound...
+ |
+LL | T: Trait<'a> + 'a,
+ | ++++
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0309`.
diff --git a/tests/ui/nll/closure-requirements/propagate-multiple-requirements.rs b/tests/ui/nll/closure-requirements/propagate-multiple-requirements.rs
new file mode 100644
index 000000000..a9d2a0771
--- /dev/null
+++ b/tests/ui/nll/closure-requirements/propagate-multiple-requirements.rs
@@ -0,0 +1,23 @@
+// Test that we propagate *all* requirements to the caller, not just the first
+// one.
+
+fn once<S, T, U, F: FnOnce(S, T) -> U>(f: F, s: S, t: T) -> U {
+ f(s, t)
+}
+
+pub fn dangle() -> &'static [i32] {
+ let other_local_arr = [0, 2, 4];
+ let local_arr = other_local_arr;
+ let mut out: &mut &'static [i32] = &mut (&[1] as _);
+ once(|mut z: &[i32], mut out_val: &mut &[i32]| {
+ // We unfortunately point to the first use in the closure in the error
+ // message
+ z = &local_arr; //~ ERROR
+ *out_val = &local_arr;
+ }, &[] as &[_], &mut *out);
+ *out
+}
+
+fn main() {
+ println!("{:?}", dangle());
+}
diff --git a/tests/ui/nll/closure-requirements/propagate-multiple-requirements.stderr b/tests/ui/nll/closure-requirements/propagate-multiple-requirements.stderr
new file mode 100644
index 000000000..2fec9bc62
--- /dev/null
+++ b/tests/ui/nll/closure-requirements/propagate-multiple-requirements.stderr
@@ -0,0 +1,17 @@
+error[E0597]: `local_arr` does not live long enough
+ --> $DIR/propagate-multiple-requirements.rs:15:14
+ |
+LL | let mut out: &mut &'static [i32] = &mut (&[1] as _);
+ | ------------------- type annotation requires that `local_arr` is borrowed for `'static`
+LL | once(|mut z: &[i32], mut out_val: &mut &[i32]| {
+ | ----------------------------------------- value captured here
+...
+LL | z = &local_arr;
+ | ^^^^^^^^^ borrowed value does not live long enough
+...
+LL | }
+ | - `local_arr` dropped here while still borrowed
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0597`.
diff --git a/tests/ui/nll/closure-requirements/region-lbr-anon-does-not-outlive-static.rs b/tests/ui/nll/closure-requirements/region-lbr-anon-does-not-outlive-static.rs
new file mode 100644
index 000000000..8147da09d
--- /dev/null
+++ b/tests/ui/nll/closure-requirements/region-lbr-anon-does-not-outlive-static.rs
@@ -0,0 +1,13 @@
+// Basic test for free regions in the NLL code. This test ought to
+// report an error due to a reborrowing constraint. Right now, we get
+// a variety of errors from the older, AST-based machinery (notably
+// borrowck), and then we get the NLL error at the end.
+
+// compile-flags:-Zverbose
+
+fn foo(x: &u32) -> &'static u32 {
+ &*x
+ //~^ ERROR lifetime may not live long enough
+}
+
+fn main() { }
diff --git a/tests/ui/nll/closure-requirements/region-lbr-anon-does-not-outlive-static.stderr b/tests/ui/nll/closure-requirements/region-lbr-anon-does-not-outlive-static.stderr
new file mode 100644
index 000000000..7034492ce
--- /dev/null
+++ b/tests/ui/nll/closure-requirements/region-lbr-anon-does-not-outlive-static.stderr
@@ -0,0 +1,10 @@
+error: lifetime may not live long enough
+ --> $DIR/region-lbr-anon-does-not-outlive-static.rs:9:5
+ |
+LL | fn foo(x: &u32) -> &'static u32 {
+ | - let's call the lifetime of this reference `'1`
+LL | &*x
+ | ^^^ returning this value requires that `'1` must outlive `'static`
+
+error: aborting due to previous error
+
diff --git a/tests/ui/nll/closure-requirements/region-lbr-named-does-not-outlive-static.rs b/tests/ui/nll/closure-requirements/region-lbr-named-does-not-outlive-static.rs
new file mode 100644
index 000000000..4acd2fc92
--- /dev/null
+++ b/tests/ui/nll/closure-requirements/region-lbr-named-does-not-outlive-static.rs
@@ -0,0 +1,13 @@
+// Basic test for free regions in the NLL code. This test ought to
+// report an error due to a reborrowing constraint. Right now, we get
+// a variety of errors from the older, AST-based machinery (notably
+// borrowck), and then we get the NLL error at the end.
+
+// compile-flags:-Zverbose
+
+fn foo<'a>(x: &'a u32) -> &'static u32 {
+ &*x
+ //~^ ERROR
+}
+
+fn main() { }
diff --git a/tests/ui/nll/closure-requirements/region-lbr-named-does-not-outlive-static.stderr b/tests/ui/nll/closure-requirements/region-lbr-named-does-not-outlive-static.stderr
new file mode 100644
index 000000000..d0a24a267
--- /dev/null
+++ b/tests/ui/nll/closure-requirements/region-lbr-named-does-not-outlive-static.stderr
@@ -0,0 +1,10 @@
+error: lifetime may not live long enough
+ --> $DIR/region-lbr-named-does-not-outlive-static.rs:9:5
+ |
+LL | fn foo<'a>(x: &'a u32) -> &'static u32 {
+ | -- lifetime `'a` defined here
+LL | &*x
+ | ^^^ returning this value requires that `'a` must outlive `'static`
+
+error: aborting due to previous error
+
diff --git a/tests/ui/nll/closure-requirements/region-lbr1-does-not-outlive-ebr2.rs b/tests/ui/nll/closure-requirements/region-lbr1-does-not-outlive-ebr2.rs
new file mode 100644
index 000000000..06e96be80
--- /dev/null
+++ b/tests/ui/nll/closure-requirements/region-lbr1-does-not-outlive-ebr2.rs
@@ -0,0 +1,13 @@
+// Basic test for free regions in the NLL code. This test ought to
+// report an error due to a reborrowing constraint. Right now, we get
+// a variety of errors from the older, AST-based machinery (notably
+// borrowck), and then we get the NLL error at the end.
+
+// compile-flags:-Zverbose
+
+fn foo<'a, 'b>(x: &'a u32, y: &'b u32) -> &'b u32 {
+ &*x
+ //~^ ERROR lifetime may not live long enough
+}
+
+fn main() {}
diff --git a/tests/ui/nll/closure-requirements/region-lbr1-does-not-outlive-ebr2.stderr b/tests/ui/nll/closure-requirements/region-lbr1-does-not-outlive-ebr2.stderr
new file mode 100644
index 000000000..d0ba53925
--- /dev/null
+++ b/tests/ui/nll/closure-requirements/region-lbr1-does-not-outlive-ebr2.stderr
@@ -0,0 +1,14 @@
+error: lifetime may not live long enough
+ --> $DIR/region-lbr1-does-not-outlive-ebr2.rs:9:5
+ |
+LL | fn foo<'a, 'b>(x: &'a u32, y: &'b u32) -> &'b u32 {
+ | -- -- lifetime `'b` defined here
+ | |
+ | lifetime `'a` defined here
+LL | &*x
+ | ^^^ function was supposed to return data with lifetime `'b` but it is returning data with lifetime `'a`
+ |
+ = help: consider adding the following bound: `'a: 'b`
+
+error: aborting due to previous error
+
diff --git a/tests/ui/nll/closure-requirements/region-lbr1-does-outlive-lbr2-because-implied-bound.rs b/tests/ui/nll/closure-requirements/region-lbr1-does-outlive-lbr2-because-implied-bound.rs
new file mode 100644
index 000000000..014959fdb
--- /dev/null
+++ b/tests/ui/nll/closure-requirements/region-lbr1-does-outlive-lbr2-because-implied-bound.rs
@@ -0,0 +1,11 @@
+// Basic test for free regions in the NLL code. This test does not
+// report an error because of the (implied) bound that `'b: 'a`.
+
+// check-pass
+// compile-flags:-Zverbose
+
+fn foo<'a, 'b>(x: &'a &'b u32) -> &'a u32 {
+ &**x
+}
+
+fn main() {}
diff --git a/tests/ui/nll/closure-requirements/return-wrong-bound-region.rs b/tests/ui/nll/closure-requirements/return-wrong-bound-region.rs
new file mode 100644
index 000000000..e34a3f6f2
--- /dev/null
+++ b/tests/ui/nll/closure-requirements/return-wrong-bound-region.rs
@@ -0,0 +1,23 @@
+// Test closure that takes two references and is supposed to return
+// the first, but actually returns the second. This should fail within
+// the closure.
+
+// compile-flags:-Zverbose
+
+#![feature(rustc_attrs)]
+
+#[rustc_regions]
+fn test() {
+ expect_sig(|a, b| b); // ought to return `a`
+ //~^ ERROR
+}
+
+fn expect_sig<F>(f: F) -> F
+ where F: for<'a> FnMut(&'a i32, &i32) -> &'a i32
+{
+ f
+}
+
+fn deref(_p: &i32) { }
+
+fn main() { }
diff --git a/tests/ui/nll/closure-requirements/return-wrong-bound-region.stderr b/tests/ui/nll/closure-requirements/return-wrong-bound-region.stderr
new file mode 100644
index 000000000..6db72b886
--- /dev/null
+++ b/tests/ui/nll/closure-requirements/return-wrong-bound-region.stderr
@@ -0,0 +1,31 @@
+note: no external requirements
+ --> $DIR/return-wrong-bound-region.rs:11:16
+ |
+LL | expect_sig(|a, b| b); // ought to return `a`
+ | ^^^^^^
+ |
+ = note: defining type: test::{closure#0} with closure substs [
+ i16,
+ for<Region(BrAnon(0, None)), Region(BrAnon(1, None))> extern "rust-call" fn((&ReLateBound(DebruijnIndex(0), BoundRegion { var: 0, kind: BrAnon(0, None) }) i32, &ReLateBound(DebruijnIndex(0), BoundRegion { var: 1, kind: BrAnon(1, None) }) i32)) -> &ReLateBound(DebruijnIndex(0), BoundRegion { var: 0, kind: BrAnon(0, None) }) i32,
+ (),
+ ]
+
+error: lifetime may not live long enough
+ --> $DIR/return-wrong-bound-region.rs:11:23
+ |
+LL | expect_sig(|a, b| b); // ought to return `a`
+ | - - ^ closure was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1`
+ | | |
+ | | has type `&'1 i32`
+ | has type `&'2 i32`
+
+note: no external requirements
+ --> $DIR/return-wrong-bound-region.rs:10:1
+ |
+LL | fn test() {
+ | ^^^^^^^^^
+ |
+ = note: defining type: test
+
+error: aborting due to previous error
+