summaryrefslogtreecommitdiffstats
path: root/src/test/ui/where-clauses
diff options
context:
space:
mode:
Diffstat (limited to 'src/test/ui/where-clauses')
-rw-r--r--src/test/ui/where-clauses/auxiliary/where_clauses_xc.rs19
-rw-r--r--src/test/ui/where-clauses/where-clause-bounds-inconsistency.rs23
-rw-r--r--src/test/ui/where-clauses/where-clause-constraints-are-local-for-inherent-impl.rs18
-rw-r--r--src/test/ui/where-clauses/where-clause-constraints-are-local-for-inherent-impl.stderr21
-rw-r--r--src/test/ui/where-clauses/where-clause-constraints-are-local-for-trait-impl.rs23
-rw-r--r--src/test/ui/where-clauses/where-clause-constraints-are-local-for-trait-impl.stderr21
-rw-r--r--src/test/ui/where-clauses/where-clause-early-bound-lifetimes.rs18
-rw-r--r--src/test/ui/where-clauses/where-clause-method-substituion-rpass.rs23
-rw-r--r--src/test/ui/where-clauses/where-clause-method-substituion.rs22
-rw-r--r--src/test/ui/where-clauses/where-clause-method-substituion.stderr15
-rw-r--r--src/test/ui/where-clauses/where-clause-region-outlives.rs12
-rw-r--r--src/test/ui/where-clauses/where-clauses-cross-crate.rs13
-rw-r--r--src/test/ui/where-clauses/where-clauses-lifetimes.rs10
-rw-r--r--src/test/ui/where-clauses/where-clauses-method-unsatisfied.rs20
-rw-r--r--src/test/ui/where-clauses/where-clauses-method-unsatisfied.stderr21
-rw-r--r--src/test/ui/where-clauses/where-clauses-method.rs20
-rw-r--r--src/test/ui/where-clauses/where-clauses-unboxed-closures.rs17
-rw-r--r--src/test/ui/where-clauses/where-clauses-unsatisfied.rs8
-rw-r--r--src/test/ui/where-clauses/where-clauses-unsatisfied.stderr19
-rw-r--r--src/test/ui/where-clauses/where-clauses.rs27
-rw-r--r--src/test/ui/where-clauses/where-equality-constraints.rs6
-rw-r--r--src/test/ui/where-clauses/where-equality-constraints.stderr18
-rw-r--r--src/test/ui/where-clauses/where-for-self-2.rs24
-rw-r--r--src/test/ui/where-clauses/where-for-self-2.stderr11
-rw-r--r--src/test/ui/where-clauses/where-for-self.rs19
-rw-r--r--src/test/ui/where-clauses/where-for-self.stderr9
-rw-r--r--src/test/ui/where-clauses/where-lifetime-resolution.rs12
-rw-r--r--src/test/ui/where-clauses/where-lifetime-resolution.stderr42
28 files changed, 511 insertions, 0 deletions
diff --git a/src/test/ui/where-clauses/auxiliary/where_clauses_xc.rs b/src/test/ui/where-clauses/auxiliary/where_clauses_xc.rs
new file mode 100644
index 000000000..7c8043b20
--- /dev/null
+++ b/src/test/ui/where-clauses/auxiliary/where_clauses_xc.rs
@@ -0,0 +1,19 @@
+pub trait Equal {
+ fn equal(&self, other: &Self) -> bool;
+ fn equals<T,U>(&self, this: &T, that: &T, x: &U, y: &U) -> bool
+ where T: Eq, U: Eq;
+}
+
+impl<T> Equal for T where T: Eq {
+ fn equal(&self, other: &T) -> bool {
+ self == other
+ }
+ fn equals<U,X>(&self, this: &U, other: &U, x: &X, y: &X) -> bool
+ where U: Eq, X: Eq {
+ this == other && x == y
+ }
+}
+
+pub fn equal<T>(x: &T, y: &T) -> bool where T: Eq {
+ x == y
+}
diff --git a/src/test/ui/where-clauses/where-clause-bounds-inconsistency.rs b/src/test/ui/where-clauses/where-clause-bounds-inconsistency.rs
new file mode 100644
index 000000000..cf7d06b61
--- /dev/null
+++ b/src/test/ui/where-clauses/where-clause-bounds-inconsistency.rs
@@ -0,0 +1,23 @@
+// run-pass
+// pretty-expanded FIXME #23616
+
+trait Bound {
+ fn dummy(&self) { }
+}
+
+trait Trait {
+ fn a<T>(&self, _: T) where T: Bound;
+ fn b<T>(&self, _: T) where T: Bound;
+ fn c<T: Bound>(&self, _: T);
+ fn d<T: Bound>(&self, _: T);
+}
+
+impl Trait for bool {
+ fn a<T: Bound>(&self, _: T) {}
+ //^~ This gets rejected but should be accepted
+ fn b<T>(&self, _: T) where T: Bound {}
+ fn c<T: Bound>(&self, _: T) {}
+ fn d<T>(&self, _: T) where T: Bound {}
+}
+
+fn main() {}
diff --git a/src/test/ui/where-clauses/where-clause-constraints-are-local-for-inherent-impl.rs b/src/test/ui/where-clauses/where-clause-constraints-are-local-for-inherent-impl.rs
new file mode 100644
index 000000000..0e8bb61a7
--- /dev/null
+++ b/src/test/ui/where-clauses/where-clause-constraints-are-local-for-inherent-impl.rs
@@ -0,0 +1,18 @@
+fn require_copy<T: Copy>(x: T) {}
+
+struct Foo<T> { x: T }
+
+// Ensure constraints are only attached to methods locally
+impl<T> Foo<T> {
+ fn needs_copy(self) where T: Copy {
+ require_copy(self.x);
+
+ }
+
+ fn fails_copy(self) {
+ require_copy(self.x);
+ //~^ ERROR the trait bound `T: Copy` is not satisfied
+ }
+}
+
+fn main() {}
diff --git a/src/test/ui/where-clauses/where-clause-constraints-are-local-for-inherent-impl.stderr b/src/test/ui/where-clauses/where-clause-constraints-are-local-for-inherent-impl.stderr
new file mode 100644
index 000000000..43fbc0a90
--- /dev/null
+++ b/src/test/ui/where-clauses/where-clause-constraints-are-local-for-inherent-impl.stderr
@@ -0,0 +1,21 @@
+error[E0277]: the trait bound `T: Copy` is not satisfied
+ --> $DIR/where-clause-constraints-are-local-for-inherent-impl.rs:13:22
+ |
+LL | require_copy(self.x);
+ | ------------ ^^^^^^ the trait `Copy` is not implemented for `T`
+ | |
+ | required by a bound introduced by this call
+ |
+note: required by a bound in `require_copy`
+ --> $DIR/where-clause-constraints-are-local-for-inherent-impl.rs:1:20
+ |
+LL | fn require_copy<T: Copy>(x: T) {}
+ | ^^^^ required by this bound in `require_copy`
+help: consider restricting type parameter `T`
+ |
+LL | impl<T: std::marker::Copy> Foo<T> {
+ | +++++++++++++++++++
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/src/test/ui/where-clauses/where-clause-constraints-are-local-for-trait-impl.rs b/src/test/ui/where-clauses/where-clause-constraints-are-local-for-trait-impl.rs
new file mode 100644
index 000000000..25c46330e
--- /dev/null
+++ b/src/test/ui/where-clauses/where-clause-constraints-are-local-for-trait-impl.rs
@@ -0,0 +1,23 @@
+fn require_copy<T: Copy>(x: T) {}
+
+struct Bar<T> { x: T }
+
+trait Foo<T> {
+ fn needs_copy(self) where T: Copy;
+ fn fails_copy(self);
+}
+
+// Ensure constraints are only attached to methods locally
+impl<T> Foo<T> for Bar<T> {
+ fn needs_copy(self) where T: Copy {
+ require_copy(self.x);
+
+ }
+
+ fn fails_copy(self) {
+ require_copy(self.x);
+ //~^ ERROR the trait bound `T: Copy` is not satisfied
+ }
+}
+
+fn main() {}
diff --git a/src/test/ui/where-clauses/where-clause-constraints-are-local-for-trait-impl.stderr b/src/test/ui/where-clauses/where-clause-constraints-are-local-for-trait-impl.stderr
new file mode 100644
index 000000000..f2db8fcc4
--- /dev/null
+++ b/src/test/ui/where-clauses/where-clause-constraints-are-local-for-trait-impl.stderr
@@ -0,0 +1,21 @@
+error[E0277]: the trait bound `T: Copy` is not satisfied
+ --> $DIR/where-clause-constraints-are-local-for-trait-impl.rs:18:22
+ |
+LL | require_copy(self.x);
+ | ------------ ^^^^^^ the trait `Copy` is not implemented for `T`
+ | |
+ | required by a bound introduced by this call
+ |
+note: required by a bound in `require_copy`
+ --> $DIR/where-clause-constraints-are-local-for-trait-impl.rs:1:20
+ |
+LL | fn require_copy<T: Copy>(x: T) {}
+ | ^^^^ required by this bound in `require_copy`
+help: consider restricting type parameter `T`
+ |
+LL | impl<T: std::marker::Copy> Foo<T> for Bar<T> {
+ | +++++++++++++++++++
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/src/test/ui/where-clauses/where-clause-early-bound-lifetimes.rs b/src/test/ui/where-clauses/where-clause-early-bound-lifetimes.rs
new file mode 100644
index 000000000..6fc570b9b
--- /dev/null
+++ b/src/test/ui/where-clauses/where-clause-early-bound-lifetimes.rs
@@ -0,0 +1,18 @@
+// run-pass
+#![allow(non_upper_case_globals)]
+
+// pretty-expanded FIXME #23616
+
+trait TheTrait { fn dummy(&self) { } }
+
+impl TheTrait for &'static isize { }
+
+fn foo<'a,T>(_: &'a T) where &'a T : TheTrait { }
+
+fn bar<T>(_: &'static T) where &'static T : TheTrait { }
+
+fn main() {
+ static x: isize = 1;
+ foo(&x);
+ bar(&x);
+}
diff --git a/src/test/ui/where-clauses/where-clause-method-substituion-rpass.rs b/src/test/ui/where-clauses/where-clause-method-substituion-rpass.rs
new file mode 100644
index 000000000..daa3c8dd8
--- /dev/null
+++ b/src/test/ui/where-clauses/where-clause-method-substituion-rpass.rs
@@ -0,0 +1,23 @@
+// run-pass
+#![allow(unused_variables)]
+// pretty-expanded FIXME #23616
+
+trait Foo<T> { fn dummy(&self, arg: T) { } }
+
+trait Bar<A> {
+ fn method<B>(&self) where A: Foo<B>;
+}
+
+struct S;
+struct X;
+
+impl Foo<S> for X {}
+
+impl Bar<X> for i32 {
+ fn method<U>(&self) where X: Foo<U> {
+ }
+}
+
+fn main() {
+ 1.method::<S>();
+}
diff --git a/src/test/ui/where-clauses/where-clause-method-substituion.rs b/src/test/ui/where-clauses/where-clause-method-substituion.rs
new file mode 100644
index 000000000..4607783c0
--- /dev/null
+++ b/src/test/ui/where-clauses/where-clause-method-substituion.rs
@@ -0,0 +1,22 @@
+trait Foo<T> {
+ fn dummy(&self, t: T) { }
+}
+
+trait Bar<A> {
+ fn method<B>(&self) where A: Foo<B>;
+}
+
+struct S;
+struct X;
+
+// Remove this impl causing the below resolution to fail // impl Foo<S> for X {}
+
+impl Bar<X> for isize {
+ fn method<U>(&self) where X: Foo<U> {
+ }
+}
+
+fn main() {
+ 1.method::<X>();
+ //~^ ERROR the trait bound `X: Foo<X>` is not satisfied
+}
diff --git a/src/test/ui/where-clauses/where-clause-method-substituion.stderr b/src/test/ui/where-clauses/where-clause-method-substituion.stderr
new file mode 100644
index 000000000..f431deee7
--- /dev/null
+++ b/src/test/ui/where-clauses/where-clause-method-substituion.stderr
@@ -0,0 +1,15 @@
+error[E0277]: the trait bound `X: Foo<X>` is not satisfied
+ --> $DIR/where-clause-method-substituion.rs:20:7
+ |
+LL | 1.method::<X>();
+ | ^^^^^^ the trait `Foo<X>` is not implemented for `X`
+ |
+note: required by a bound in `Bar::method`
+ --> $DIR/where-clause-method-substituion.rs:6:34
+ |
+LL | fn method<B>(&self) where A: Foo<B>;
+ | ^^^^^^ required by this bound in `Bar::method`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/src/test/ui/where-clauses/where-clause-region-outlives.rs b/src/test/ui/where-clauses/where-clause-region-outlives.rs
new file mode 100644
index 000000000..84925345d
--- /dev/null
+++ b/src/test/ui/where-clauses/where-clause-region-outlives.rs
@@ -0,0 +1,12 @@
+// run-pass
+#![allow(dead_code)]
+#![allow(unused_variables)]
+// pretty-expanded FIXME #23616
+
+struct A<'a, 'b> where 'a : 'b { x: &'a isize, y: &'b isize }
+
+fn main() {
+ let x = 1;
+ let y = 1;
+ let a = A { x: &x, y: &y };
+}
diff --git a/src/test/ui/where-clauses/where-clauses-cross-crate.rs b/src/test/ui/where-clauses/where-clauses-cross-crate.rs
new file mode 100644
index 000000000..9edf0bd5b
--- /dev/null
+++ b/src/test/ui/where-clauses/where-clauses-cross-crate.rs
@@ -0,0 +1,13 @@
+// run-pass
+// aux-build:where_clauses_xc.rs
+
+extern crate where_clauses_xc;
+
+use where_clauses_xc::{Equal, equal};
+
+fn main() {
+ println!("{}", equal(&1, &2));
+ println!("{}", equal(&1, &1));
+ println!("{}", "hello".equal(&"hello"));
+ println!("{}", "hello".equals::<isize,&str>(&1, &1, &"foo", &"bar"));
+}
diff --git a/src/test/ui/where-clauses/where-clauses-lifetimes.rs b/src/test/ui/where-clauses/where-clauses-lifetimes.rs
new file mode 100644
index 000000000..4bfd9e659
--- /dev/null
+++ b/src/test/ui/where-clauses/where-clauses-lifetimes.rs
@@ -0,0 +1,10 @@
+// run-pass
+#![allow(unused_mut)]
+#![allow(unused_variables)]
+// pretty-expanded FIXME #23616
+
+fn foo<'a, I>(mut it: I) where I: Iterator<Item=&'a isize> {}
+
+fn main() {
+ foo([1, 2].iter());
+}
diff --git a/src/test/ui/where-clauses/where-clauses-method-unsatisfied.rs b/src/test/ui/where-clauses/where-clauses-method-unsatisfied.rs
new file mode 100644
index 000000000..a8ae02964
--- /dev/null
+++ b/src/test/ui/where-clauses/where-clauses-method-unsatisfied.rs
@@ -0,0 +1,20 @@
+// Test that a where clause attached to a method allows us to add
+// additional constraints to a parameter out of scope.
+
+struct Foo<T> {
+ value: T
+}
+
+struct Bar; // does not implement Eq
+
+impl<T> Foo<T> {
+ fn equals(&self, u: &Foo<T>) -> bool where T : Eq {
+ self.value == u.value
+ }
+}
+
+fn main() {
+ let x = Foo { value: Bar };
+ x.equals(&x);
+ //~^ ERROR `Bar: Eq` is not satisfied
+}
diff --git a/src/test/ui/where-clauses/where-clauses-method-unsatisfied.stderr b/src/test/ui/where-clauses/where-clauses-method-unsatisfied.stderr
new file mode 100644
index 000000000..c13552bc2
--- /dev/null
+++ b/src/test/ui/where-clauses/where-clauses-method-unsatisfied.stderr
@@ -0,0 +1,21 @@
+error[E0277]: the trait bound `Bar: Eq` is not satisfied
+ --> $DIR/where-clauses-method-unsatisfied.rs:18:14
+ |
+LL | x.equals(&x);
+ | ------ ^^ the trait `Eq` is not implemented for `Bar`
+ | |
+ | required by a bound introduced by this call
+ |
+note: required by a bound in `Foo::<T>::equals`
+ --> $DIR/where-clauses-method-unsatisfied.rs:11:52
+ |
+LL | fn equals(&self, u: &Foo<T>) -> bool where T : Eq {
+ | ^^ required by this bound in `Foo::<T>::equals`
+help: consider annotating `Bar` with `#[derive(Eq)]`
+ |
+LL | #[derive(Eq)]
+ |
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/src/test/ui/where-clauses/where-clauses-method.rs b/src/test/ui/where-clauses/where-clauses-method.rs
new file mode 100644
index 000000000..feecff435
--- /dev/null
+++ b/src/test/ui/where-clauses/where-clauses-method.rs
@@ -0,0 +1,20 @@
+// run-pass
+// Test that a where clause attached to a method allows us to add
+// additional constraints to a parameter out of scope.
+
+struct Foo<T> {
+ value: T
+}
+
+impl<T> Foo<T> {
+ fn equals(&self, u: &Foo<T>) -> bool where T : Eq {
+ self.value == u.value
+ }
+}
+
+fn main() {
+ let x = Foo { value: 1 };
+ let y = Foo { value: 2 };
+ println!("{}", x.equals(&x));
+ println!("{}", x.equals(&y));
+}
diff --git a/src/test/ui/where-clauses/where-clauses-unboxed-closures.rs b/src/test/ui/where-clauses/where-clauses-unboxed-closures.rs
new file mode 100644
index 000000000..6964cfa2e
--- /dev/null
+++ b/src/test/ui/where-clauses/where-clauses-unboxed-closures.rs
@@ -0,0 +1,17 @@
+// run-pass
+#![allow(unused_variables)]
+// pretty-expanded FIXME #23616
+
+struct Bencher;
+
+// ICE
+fn warm_up<'a, F>(f: F) where F: Fn(&'a mut Bencher) {
+}
+
+fn main() {
+ // ICE trigger
+ warm_up(|b: &mut Bencher| () );
+
+ // OK
+ warm_up(|b| () );
+}
diff --git a/src/test/ui/where-clauses/where-clauses-unsatisfied.rs b/src/test/ui/where-clauses/where-clauses-unsatisfied.rs
new file mode 100644
index 000000000..8b067d30a
--- /dev/null
+++ b/src/test/ui/where-clauses/where-clauses-unsatisfied.rs
@@ -0,0 +1,8 @@
+fn equal<T>(a: &T, b: &T) -> bool where T : Eq { a == b }
+
+struct Struct;
+
+fn main() {
+ drop(equal(&Struct, &Struct))
+ //~^ ERROR the trait bound `Struct: Eq` is not satisfied
+}
diff --git a/src/test/ui/where-clauses/where-clauses-unsatisfied.stderr b/src/test/ui/where-clauses/where-clauses-unsatisfied.stderr
new file mode 100644
index 000000000..b1805a452
--- /dev/null
+++ b/src/test/ui/where-clauses/where-clauses-unsatisfied.stderr
@@ -0,0 +1,19 @@
+error[E0277]: the trait bound `Struct: Eq` is not satisfied
+ --> $DIR/where-clauses-unsatisfied.rs:6:10
+ |
+LL | drop(equal(&Struct, &Struct))
+ | ^^^^^ the trait `Eq` is not implemented for `Struct`
+ |
+note: required by a bound in `equal`
+ --> $DIR/where-clauses-unsatisfied.rs:1:45
+ |
+LL | fn equal<T>(a: &T, b: &T) -> bool where T : Eq { a == b }
+ | ^^ required by this bound in `equal`
+help: consider annotating `Struct` with `#[derive(Eq)]`
+ |
+LL | #[derive(Eq)]
+ |
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/src/test/ui/where-clauses/where-clauses.rs b/src/test/ui/where-clauses/where-clauses.rs
new file mode 100644
index 000000000..905ef7c5e
--- /dev/null
+++ b/src/test/ui/where-clauses/where-clauses.rs
@@ -0,0 +1,27 @@
+// run-pass
+trait Equal {
+ fn equal(&self, other: &Self) -> bool;
+ fn equals<T,U>(&self, this: &T, that: &T, x: &U, y: &U) -> bool
+ where T: Eq, U: Eq;
+}
+
+impl<T> Equal for T where T: Eq {
+ fn equal(&self, other: &T) -> bool {
+ self == other
+ }
+ fn equals<U,X>(&self, this: &U, other: &U, x: &X, y: &X) -> bool
+ where U: Eq, X: Eq {
+ this == other && x == y
+ }
+}
+
+fn equal<T>(x: &T, y: &T) -> bool where T: Eq {
+ x == y
+}
+
+fn main() {
+ println!("{}", equal(&1, &2));
+ println!("{}", equal(&1, &1));
+ println!("{}", "hello".equal(&"hello"));
+ println!("{}", "hello".equals::<isize,&str>(&1, &1, &"foo", &"bar"));
+}
diff --git a/src/test/ui/where-clauses/where-equality-constraints.rs b/src/test/ui/where-clauses/where-equality-constraints.rs
new file mode 100644
index 000000000..8828f09d9
--- /dev/null
+++ b/src/test/ui/where-clauses/where-equality-constraints.rs
@@ -0,0 +1,6 @@
+fn f() where u8 = u16 {}
+//~^ ERROR equality constraints are not yet supported in `where` clauses
+fn g() where for<'a> &'static (u8,) == u16, {}
+//~^ ERROR equality constraints are not yet supported in `where` clauses
+
+fn main() {}
diff --git a/src/test/ui/where-clauses/where-equality-constraints.stderr b/src/test/ui/where-clauses/where-equality-constraints.stderr
new file mode 100644
index 000000000..9d8fac02e
--- /dev/null
+++ b/src/test/ui/where-clauses/where-equality-constraints.stderr
@@ -0,0 +1,18 @@
+error: equality constraints are not yet supported in `where` clauses
+ --> $DIR/where-equality-constraints.rs:1:14
+ |
+LL | fn f() where u8 = u16 {}
+ | ^^^^^^^^ not supported
+ |
+ = note: see issue #20041 <https://github.com/rust-lang/rust/issues/20041> for more information
+
+error: equality constraints are not yet supported in `where` clauses
+ --> $DIR/where-equality-constraints.rs:3:14
+ |
+LL | fn g() where for<'a> &'static (u8,) == u16, {}
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not supported
+ |
+ = note: see issue #20041 <https://github.com/rust-lang/rust/issues/20041> for more information
+
+error: aborting due to 2 previous errors
+
diff --git a/src/test/ui/where-clauses/where-for-self-2.rs b/src/test/ui/where-clauses/where-for-self-2.rs
new file mode 100644
index 000000000..37c6954fd
--- /dev/null
+++ b/src/test/ui/where-clauses/where-for-self-2.rs
@@ -0,0 +1,24 @@
+// Test that we can quantify lifetimes outside a constraint (i.e., including
+// the self type) in a where clause. Specifically, test that implementing for a
+// specific lifetime is not enough to satisfy the `for<'a> ...` constraint, which
+// should require *all* lifetimes.
+
+static X: &'static u32 = &42;
+
+trait Bar {
+ fn bar(&self);
+}
+
+impl Bar for &'static u32 {
+ fn bar(&self) {}
+}
+
+fn foo<T>(x: &T)
+where
+ for<'a> &'a T: Bar,
+{
+}
+
+fn main() {
+ foo(&X); //~ ERROR implementation of `Bar` is not general enough
+}
diff --git a/src/test/ui/where-clauses/where-for-self-2.stderr b/src/test/ui/where-clauses/where-for-self-2.stderr
new file mode 100644
index 000000000..f65db78fc
--- /dev/null
+++ b/src/test/ui/where-clauses/where-for-self-2.stderr
@@ -0,0 +1,11 @@
+error: implementation of `Bar` is not general enough
+ --> $DIR/where-for-self-2.rs:23:5
+ |
+LL | foo(&X);
+ | ^^^^^^^ implementation of `Bar` is not general enough
+ |
+ = note: `&'0 u32` must implement `Bar`, for any lifetime `'0`...
+ = note: ...but `Bar` is actually implemented for the type `&'static u32`
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/where-clauses/where-for-self.rs b/src/test/ui/where-clauses/where-for-self.rs
new file mode 100644
index 000000000..9380e72cd
--- /dev/null
+++ b/src/test/ui/where-clauses/where-for-self.rs
@@ -0,0 +1,19 @@
+// Test that we can quantify lifetimes outside a constraint (i.e., including
+// the self type) in a where clause. Specifically, test that we cannot nest
+// quantification in constraints (to be clear, there is no reason this should not
+// we're testing we don't crash or do something stupid).
+
+trait Bar<'a> {
+ fn bar(&self);
+}
+
+impl<'a, 'b> Bar<'b> for &'a u32 {
+ fn bar(&self) {}
+}
+
+fn foo<T>(x: &T)
+ where for<'a> &'a T: for<'b> Bar<'b>
+ //~^ error: nested quantification of lifetimes
+{}
+
+fn main() {}
diff --git a/src/test/ui/where-clauses/where-for-self.stderr b/src/test/ui/where-clauses/where-for-self.stderr
new file mode 100644
index 000000000..d06afc1e4
--- /dev/null
+++ b/src/test/ui/where-clauses/where-for-self.stderr
@@ -0,0 +1,9 @@
+error[E0316]: nested quantification of lifetimes
+ --> $DIR/where-for-self.rs:15:26
+ |
+LL | where for<'a> &'a T: for<'b> Bar<'b>
+ | ^^^^^^^^^^^^^^^
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0316`.
diff --git a/src/test/ui/where-clauses/where-lifetime-resolution.rs b/src/test/ui/where-clauses/where-lifetime-resolution.rs
new file mode 100644
index 000000000..d8677ee95
--- /dev/null
+++ b/src/test/ui/where-clauses/where-lifetime-resolution.rs
@@ -0,0 +1,12 @@
+trait Trait1<'a> {}
+trait Trait2<'a, 'b> {}
+
+fn f() where
+ for<'a> dyn Trait1<'a>: Trait1<'a>, // OK
+ (dyn for<'a> Trait1<'a>): Trait1<'a>,
+ //~^ ERROR use of undeclared lifetime name `'a`
+ for<'a> dyn for<'b> Trait2<'a, 'b>: Trait2<'a, 'b>,
+ //~^ ERROR use of undeclared lifetime name `'b`
+{}
+
+fn main() {}
diff --git a/src/test/ui/where-clauses/where-lifetime-resolution.stderr b/src/test/ui/where-clauses/where-lifetime-resolution.stderr
new file mode 100644
index 000000000..e8df02fba
--- /dev/null
+++ b/src/test/ui/where-clauses/where-lifetime-resolution.stderr
@@ -0,0 +1,42 @@
+error[E0261]: use of undeclared lifetime name `'a`
+ --> $DIR/where-lifetime-resolution.rs:6:38
+ |
+LL | (dyn for<'a> Trait1<'a>): Trait1<'a>,
+ | ^^ undeclared lifetime
+ |
+ = note: for more information on higher-ranked polymorphism, visit https://doc.rust-lang.org/nomicon/hrtb.html
+help: consider making the bound lifetime-generic with a new `'a` lifetime
+ |
+LL | (dyn for<'a> Trait1<'a>): for<'a> Trait1<'a>,
+ | +++++++
+help: consider making the bound lifetime-generic with a new `'a` lifetime
+ |
+LL | for<'a> (dyn for<'a> Trait1<'a>): Trait1<'a>,
+ | +++++++
+help: consider introducing lifetime `'a` here
+ |
+LL | fn f<'a>() where
+ | ++++
+
+error[E0261]: use of undeclared lifetime name `'b`
+ --> $DIR/where-lifetime-resolution.rs:8:52
+ |
+LL | for<'a> dyn for<'b> Trait2<'a, 'b>: Trait2<'a, 'b>,
+ | ^^ undeclared lifetime
+ |
+help: consider making the bound lifetime-generic with a new `'b` lifetime
+ |
+LL | for<'a> dyn for<'b> Trait2<'a, 'b>: for<'b> Trait2<'a, 'b>,
+ | +++++++
+help: consider making the bound lifetime-generic with a new `'b` lifetime
+ |
+LL | for<'b, 'a> dyn for<'b> Trait2<'a, 'b>: Trait2<'a, 'b>,
+ | +++
+help: consider introducing lifetime `'b` here
+ |
+LL | fn f<'b>() where
+ | ++++
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0261`.