summaryrefslogtreecommitdiffstats
path: root/src/test/ui/variance
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--src/test/ui/variance-intersection-of-ref-and-opt-ref.rs25
-rw-r--r--src/test/ui/variance-iterators-in-libcore.rs10
-rw-r--r--src/test/ui/variance/variance-associated-consts.rs17
-rw-r--r--src/test/ui/variance/variance-associated-consts.stderr8
-rw-r--r--src/test/ui/variance/variance-associated-types.rs22
-rw-r--r--src/test/ui/variance/variance-associated-types.stderr14
-rw-r--r--src/test/ui/variance/variance-associated-types2.rs17
-rw-r--r--src/test/ui/variance/variance-associated-types2.stderr10
-rw-r--r--src/test/ui/variance/variance-btree-invariant-types.rs80
-rw-r--r--src/test/ui/variance/variance-btree-invariant-types.stderr202
-rw-r--r--src/test/ui/variance/variance-cell-is-invariant.rs19
-rw-r--r--src/test/ui/variance/variance-cell-is-invariant.stderr18
-rw-r--r--src/test/ui/variance/variance-contravariant-arg-object.rs27
-rw-r--r--src/test/ui/variance/variance-contravariant-arg-object.stderr28
-rw-r--r--src/test/ui/variance/variance-contravariant-arg-trait-match.rs28
-rw-r--r--src/test/ui/variance/variance-contravariant-arg-trait-match.stderr28
-rw-r--r--src/test/ui/variance/variance-contravariant-self-trait-match.rs29
-rw-r--r--src/test/ui/variance/variance-contravariant-self-trait-match.stderr28
-rw-r--r--src/test/ui/variance/variance-covariant-arg-object.rs27
-rw-r--r--src/test/ui/variance/variance-covariant-arg-object.stderr28
-rw-r--r--src/test/ui/variance/variance-covariant-arg-trait-match.rs27
-rw-r--r--src/test/ui/variance/variance-covariant-arg-trait-match.stderr28
-rw-r--r--src/test/ui/variance/variance-covariant-self-trait-match.rs27
-rw-r--r--src/test/ui/variance/variance-covariant-self-trait-match.stderr28
-rw-r--r--src/test/ui/variance/variance-invariant-arg-object.rs23
-rw-r--r--src/test/ui/variance/variance-invariant-arg-object.stderr28
-rw-r--r--src/test/ui/variance/variance-invariant-arg-trait-match.rs23
-rw-r--r--src/test/ui/variance/variance-invariant-arg-trait-match.stderr28
-rw-r--r--src/test/ui/variance/variance-invariant-self-trait-match.rs23
-rw-r--r--src/test/ui/variance/variance-invariant-self-trait-match.stderr28
-rw-r--r--src/test/ui/variance/variance-issue-20533.rs43
-rw-r--r--src/test/ui/variance/variance-issue-20533.stderr33
-rw-r--r--src/test/ui/variance/variance-object-types.rs12
-rw-r--r--src/test/ui/variance/variance-object-types.stderr8
-rw-r--r--src/test/ui/variance/variance-regions-direct.rs65
-rw-r--r--src/test/ui/variance/variance-regions-direct.stderr44
-rw-r--r--src/test/ui/variance/variance-regions-indirect.rs34
-rw-r--r--src/test/ui/variance/variance-regions-indirect.stderr32
-rw-r--r--src/test/ui/variance/variance-regions-unused-direct.rs15
-rw-r--r--src/test/ui/variance/variance-regions-unused-direct.stderr19
-rw-r--r--src/test/ui/variance/variance-regions-unused-indirect.rs11
-rw-r--r--src/test/ui/variance/variance-regions-unused-indirect.stderr19
-rw-r--r--src/test/ui/variance/variance-trait-bounds.rs35
-rw-r--r--src/test/ui/variance/variance-trait-bounds.stderr26
-rw-r--r--src/test/ui/variance/variance-trait-matching.rs38
-rw-r--r--src/test/ui/variance/variance-trait-matching.stderr12
-rw-r--r--src/test/ui/variance/variance-trait-object-bound.rs18
-rw-r--r--src/test/ui/variance/variance-trait-object-bound.stderr8
-rw-r--r--src/test/ui/variance/variance-types-bounds.rs43
-rw-r--r--src/test/ui/variance/variance-types-bounds.stderr32
-rw-r--r--src/test/ui/variance/variance-types.rs41
-rw-r--r--src/test/ui/variance/variance-types.stderr38
-rw-r--r--src/test/ui/variance/variance-unused-region-param.rs7
-rw-r--r--src/test/ui/variance/variance-unused-region-param.stderr19
-rw-r--r--src/test/ui/variance/variance-unused-type-param.rs28
-rw-r--r--src/test/ui/variance/variance-unused-type-param.stderr54
-rw-r--r--src/test/ui/variance/variance-use-contravariant-struct-1.rs15
-rw-r--r--src/test/ui/variance/variance-use-contravariant-struct-1.stderr15
-rw-r--r--src/test/ui/variance/variance-use-contravariant-struct-2.rs17
-rw-r--r--src/test/ui/variance/variance-use-covariant-struct-1.rs14
-rw-r--r--src/test/ui/variance/variance-use-covariant-struct-1.stderr15
-rw-r--r--src/test/ui/variance/variance-use-covariant-struct-2.rs16
-rw-r--r--src/test/ui/variance/variance-use-invariant-struct-1.rs23
-rw-r--r--src/test/ui/variance/variance-use-invariant-struct-1.stderr34
64 files changed, 1811 insertions, 0 deletions
diff --git a/src/test/ui/variance-intersection-of-ref-and-opt-ref.rs b/src/test/ui/variance-intersection-of-ref-and-opt-ref.rs
new file mode 100644
index 000000000..74707a98d
--- /dev/null
+++ b/src/test/ui/variance-intersection-of-ref-and-opt-ref.rs
@@ -0,0 +1,25 @@
+// run-pass
+// Elaborated version of the opening example from RFC 738. This failed
+// to compile before variance because invariance of `Option` prevented
+// us from approximating the lifetimes of `field1` and `field2` to a
+// common intersection.
+
+#![allow(dead_code)]
+
+struct List<'l> {
+ field1: &'l i32,
+ field2: Option<&'l i32>,
+}
+
+fn foo(field1: &i32, field2: Option<&i32>) -> i32 {
+ let list = List { field1: field1, field2: field2 };
+ *list.field1 + list.field2.cloned().unwrap_or(0)
+}
+
+fn main() {
+ let x = 22;
+ let y = Some(3);
+ let z = None;
+ assert_eq!(foo(&x, y.as_ref()), 25);
+ assert_eq!(foo(&x, z.as_ref()), 22);
+}
diff --git a/src/test/ui/variance-iterators-in-libcore.rs b/src/test/ui/variance-iterators-in-libcore.rs
new file mode 100644
index 000000000..a542e44d5
--- /dev/null
+++ b/src/test/ui/variance-iterators-in-libcore.rs
@@ -0,0 +1,10 @@
+// run-pass
+
+#![allow(dead_code)]
+
+use std::iter::{Fuse, Zip};
+
+fn fuse_covariant<'a, I>(iter: Fuse<&'static I>) -> Fuse<&'a I> { iter }
+fn zip_covariant<'a, A, B>(iter: Zip<&'static A, &'static B>) -> Zip<&'a A, &'a B> { iter }
+
+fn main() { }
diff --git a/src/test/ui/variance/variance-associated-consts.rs b/src/test/ui/variance/variance-associated-consts.rs
new file mode 100644
index 000000000..da55bc962
--- /dev/null
+++ b/src/test/ui/variance/variance-associated-consts.rs
@@ -0,0 +1,17 @@
+// Test that the variance computation considers types that
+// appear in const expressions to be invariant.
+
+#![feature(rustc_attrs)]
+#![allow(incomplete_features)]
+#![feature(generic_const_exprs)]
+
+trait Trait {
+ const Const: usize;
+}
+
+#[rustc_variance]
+struct Foo<T: Trait> { //~ ERROR [o]
+ field: [u8; <T as Trait>::Const]
+}
+
+fn main() { }
diff --git a/src/test/ui/variance/variance-associated-consts.stderr b/src/test/ui/variance/variance-associated-consts.stderr
new file mode 100644
index 000000000..219f5bca9
--- /dev/null
+++ b/src/test/ui/variance/variance-associated-consts.stderr
@@ -0,0 +1,8 @@
+error[E0208]: [o]
+ --> $DIR/variance-associated-consts.rs:13:1
+ |
+LL | struct Foo<T: Trait> {
+ | ^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/variance/variance-associated-types.rs b/src/test/ui/variance/variance-associated-types.rs
new file mode 100644
index 000000000..1165fb53c
--- /dev/null
+++ b/src/test/ui/variance/variance-associated-types.rs
@@ -0,0 +1,22 @@
+// Test that the variance computation considers types/regions that
+// appear in projections to be invariant.
+
+#![feature(rustc_attrs)]
+
+trait Trait<'a> {
+ type Type;
+
+ fn method(&'a self) { }
+}
+
+#[rustc_variance]
+struct Foo<'a, T : Trait<'a>> { //~ ERROR [-, +]
+ field: (T, &'a ())
+}
+
+#[rustc_variance]
+struct Bar<'a, T : Trait<'a>> { //~ ERROR [o, o]
+ field: <T as Trait<'a>>::Type
+}
+
+fn main() { }
diff --git a/src/test/ui/variance/variance-associated-types.stderr b/src/test/ui/variance/variance-associated-types.stderr
new file mode 100644
index 000000000..94f770eda
--- /dev/null
+++ b/src/test/ui/variance/variance-associated-types.stderr
@@ -0,0 +1,14 @@
+error[E0208]: [-, +]
+ --> $DIR/variance-associated-types.rs:13:1
+ |
+LL | struct Foo<'a, T : Trait<'a>> {
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error[E0208]: [o, o]
+ --> $DIR/variance-associated-types.rs:18:1
+ |
+LL | struct Bar<'a, T : Trait<'a>> {
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to 2 previous errors
+
diff --git a/src/test/ui/variance/variance-associated-types2.rs b/src/test/ui/variance/variance-associated-types2.rs
new file mode 100644
index 000000000..e487eefea
--- /dev/null
+++ b/src/test/ui/variance/variance-associated-types2.rs
@@ -0,0 +1,17 @@
+// Test that dyn Foo<Bar = T> is invariant with respect to T.
+// Failure to enforce invariance here can be weaponized, see #71550 for details.
+
+trait Foo {
+ type Bar;
+}
+
+fn make() -> Box<dyn Foo<Bar = &'static u32>> {
+ panic!()
+}
+
+fn take<'a>(_: &'a u32) {
+ let _: Box<dyn Foo<Bar = &'a u32>> = make();
+ //~^ ERROR lifetime may not live long enough
+}
+
+fn main() {}
diff --git a/src/test/ui/variance/variance-associated-types2.stderr b/src/test/ui/variance/variance-associated-types2.stderr
new file mode 100644
index 000000000..35871c123
--- /dev/null
+++ b/src/test/ui/variance/variance-associated-types2.stderr
@@ -0,0 +1,10 @@
+error: lifetime may not live long enough
+ --> $DIR/variance-associated-types2.rs:13:12
+ |
+LL | fn take<'a>(_: &'a u32) {
+ | -- lifetime `'a` defined here
+LL | let _: Box<dyn Foo<Bar = &'a u32>> = make();
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ type annotation requires that `'a` must outlive `'static`
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/variance/variance-btree-invariant-types.rs b/src/test/ui/variance/variance-btree-invariant-types.rs
new file mode 100644
index 000000000..09c93d001
--- /dev/null
+++ b/src/test/ui/variance/variance-btree-invariant-types.rs
@@ -0,0 +1,80 @@
+use std::collections::btree_map::{IterMut, OccupiedEntry, RangeMut, VacantEntry};
+
+fn iter_cov_key<'a, 'new>(v: IterMut<'a, &'static (), ()>) -> IterMut<'a, &'new (), ()> {
+ v
+ //~^ lifetime may not live long enough
+}
+fn iter_cov_val<'a, 'new>(v: IterMut<'a, (), &'static ()>) -> IterMut<'a, (), &'new ()> {
+ v
+ //~^ lifetime may not live long enough
+}
+fn iter_contra_key<'a, 'new>(v: IterMut<'a, &'new (), ()>) -> IterMut<'a, &'static (), ()> {
+ v
+ //~^ lifetime may not live long enough
+}
+fn iter_contra_val<'a, 'new>(v: IterMut<'a, (), &'new ()>) -> IterMut<'a, (), &'static ()> {
+ v
+ //~^ lifetime may not live long enough
+}
+
+fn range_cov_key<'a, 'new>(v: RangeMut<'a, &'static (), ()>) -> RangeMut<'a, &'new (), ()> {
+ v
+ //~^ lifetime may not live long enough
+}
+fn range_cov_val<'a, 'new>(v: RangeMut<'a, (), &'static ()>) -> RangeMut<'a, (), &'new ()> {
+ v
+ //~^ lifetime may not live long enough
+}
+fn range_contra_key<'a, 'new>(v: RangeMut<'a, &'new (), ()>) -> RangeMut<'a, &'static (), ()> {
+ v
+ //~^ lifetime may not live long enough
+}
+fn range_contra_val<'a, 'new>(v: RangeMut<'a, (), &'new ()>) -> RangeMut<'a, (), &'static ()> {
+ v
+ //~^ lifetime may not live long enough
+}
+
+fn occ_cov_key<'a, 'new>(v: OccupiedEntry<'a, &'static (), ()>)
+ -> OccupiedEntry<'a, &'new (), ()> {
+ v
+ //~^ lifetime may not live long enough
+}
+fn occ_cov_val<'a, 'new>(v: OccupiedEntry<'a, (), &'static ()>)
+ -> OccupiedEntry<'a, (), &'new ()> {
+ v
+ //~^ lifetime may not live long enough
+}
+fn occ_contra_key<'a, 'new>(v: OccupiedEntry<'a, &'new (), ()>)
+ -> OccupiedEntry<'a, &'static (), ()> {
+ v
+ //~^ lifetime may not live long enough
+}
+fn occ_contra_val<'a, 'new>(v: OccupiedEntry<'a, (), &'new ()>)
+ -> OccupiedEntry<'a, (), &'static ()> {
+ v
+ //~^ lifetime may not live long enough
+}
+
+fn vac_cov_key<'a, 'new>(v: VacantEntry<'a, &'static (), ()>)
+ -> VacantEntry<'a, &'new (), ()> {
+ v
+ //~^ lifetime may not live long enough
+}
+fn vac_cov_val<'a, 'new>(v: VacantEntry<'a, (), &'static ()>)
+ -> VacantEntry<'a, (), &'new ()> {
+ v
+ //~^ lifetime may not live long enough
+}
+fn vac_contra_key<'a, 'new>(v: VacantEntry<'a, &'new (), ()>)
+ -> VacantEntry<'a, &'static (), ()> {
+ v
+ //~^ lifetime may not live long enough
+}
+fn vac_contra_val<'a, 'new>(v: VacantEntry<'a, (), &'new ()>)
+ -> VacantEntry<'a, (), &'static ()> {
+ v
+ //~^ lifetime may not live long enough
+}
+
+
+fn main() { }
diff --git a/src/test/ui/variance/variance-btree-invariant-types.stderr b/src/test/ui/variance/variance-btree-invariant-types.stderr
new file mode 100644
index 000000000..6f7910021
--- /dev/null
+++ b/src/test/ui/variance/variance-btree-invariant-types.stderr
@@ -0,0 +1,202 @@
+error: lifetime may not live long enough
+ --> $DIR/variance-btree-invariant-types.rs:4:5
+ |
+LL | fn iter_cov_key<'a, 'new>(v: IterMut<'a, &'static (), ()>) -> IterMut<'a, &'new (), ()> {
+ | ---- lifetime `'new` defined here
+LL | v
+ | ^ returning this value requires that `'new` must outlive `'static`
+ |
+ = note: requirement occurs because of the type `std::collections::btree_map::IterMut<'_, &(), ()>`, which makes the generic argument `&()` invariant
+ = note: the struct `std::collections::btree_map::IterMut<'a, K, V>` is invariant over the parameter `K`
+ = help: see <https://doc.rust-lang.org/nomicon/subtyping.html> for more information about variance
+
+error: lifetime may not live long enough
+ --> $DIR/variance-btree-invariant-types.rs:8:5
+ |
+LL | fn iter_cov_val<'a, 'new>(v: IterMut<'a, (), &'static ()>) -> IterMut<'a, (), &'new ()> {
+ | ---- lifetime `'new` defined here
+LL | v
+ | ^ returning this value requires that `'new` must outlive `'static`
+ |
+ = note: requirement occurs because of the type `std::collections::btree_map::IterMut<'_, (), &()>`, which makes the generic argument `()` invariant
+ = note: the struct `std::collections::btree_map::IterMut<'a, K, V>` is invariant over the parameter `K`
+ = help: see <https://doc.rust-lang.org/nomicon/subtyping.html> for more information about variance
+
+error: lifetime may not live long enough
+ --> $DIR/variance-btree-invariant-types.rs:12:5
+ |
+LL | fn iter_contra_key<'a, 'new>(v: IterMut<'a, &'new (), ()>) -> IterMut<'a, &'static (), ()> {
+ | ---- lifetime `'new` defined here
+LL | v
+ | ^ returning this value requires that `'new` must outlive `'static`
+ |
+ = note: requirement occurs because of the type `std::collections::btree_map::IterMut<'_, &(), ()>`, which makes the generic argument `&()` invariant
+ = note: the struct `std::collections::btree_map::IterMut<'a, K, V>` is invariant over the parameter `K`
+ = help: see <https://doc.rust-lang.org/nomicon/subtyping.html> for more information about variance
+
+error: lifetime may not live long enough
+ --> $DIR/variance-btree-invariant-types.rs:16:5
+ |
+LL | fn iter_contra_val<'a, 'new>(v: IterMut<'a, (), &'new ()>) -> IterMut<'a, (), &'static ()> {
+ | ---- lifetime `'new` defined here
+LL | v
+ | ^ returning this value requires that `'new` must outlive `'static`
+ |
+ = note: requirement occurs because of the type `std::collections::btree_map::IterMut<'_, (), &()>`, which makes the generic argument `()` invariant
+ = note: the struct `std::collections::btree_map::IterMut<'a, K, V>` is invariant over the parameter `K`
+ = help: see <https://doc.rust-lang.org/nomicon/subtyping.html> for more information about variance
+
+error: lifetime may not live long enough
+ --> $DIR/variance-btree-invariant-types.rs:21:5
+ |
+LL | fn range_cov_key<'a, 'new>(v: RangeMut<'a, &'static (), ()>) -> RangeMut<'a, &'new (), ()> {
+ | ---- lifetime `'new` defined here
+LL | v
+ | ^ returning this value requires that `'new` must outlive `'static`
+ |
+ = note: requirement occurs because of the type `RangeMut<'_, &(), ()>`, which makes the generic argument `&()` invariant
+ = note: the struct `RangeMut<'a, K, V>` is invariant over the parameter `K`
+ = help: see <https://doc.rust-lang.org/nomicon/subtyping.html> for more information about variance
+
+error: lifetime may not live long enough
+ --> $DIR/variance-btree-invariant-types.rs:25:5
+ |
+LL | fn range_cov_val<'a, 'new>(v: RangeMut<'a, (), &'static ()>) -> RangeMut<'a, (), &'new ()> {
+ | ---- lifetime `'new` defined here
+LL | v
+ | ^ returning this value requires that `'new` must outlive `'static`
+ |
+ = note: requirement occurs because of the type `RangeMut<'_, (), &()>`, which makes the generic argument `()` invariant
+ = note: the struct `RangeMut<'a, K, V>` is invariant over the parameter `K`
+ = help: see <https://doc.rust-lang.org/nomicon/subtyping.html> for more information about variance
+
+error: lifetime may not live long enough
+ --> $DIR/variance-btree-invariant-types.rs:29:5
+ |
+LL | fn range_contra_key<'a, 'new>(v: RangeMut<'a, &'new (), ()>) -> RangeMut<'a, &'static (), ()> {
+ | ---- lifetime `'new` defined here
+LL | v
+ | ^ returning this value requires that `'new` must outlive `'static`
+ |
+ = note: requirement occurs because of the type `RangeMut<'_, &(), ()>`, which makes the generic argument `&()` invariant
+ = note: the struct `RangeMut<'a, K, V>` is invariant over the parameter `K`
+ = help: see <https://doc.rust-lang.org/nomicon/subtyping.html> for more information about variance
+
+error: lifetime may not live long enough
+ --> $DIR/variance-btree-invariant-types.rs:33:5
+ |
+LL | fn range_contra_val<'a, 'new>(v: RangeMut<'a, (), &'new ()>) -> RangeMut<'a, (), &'static ()> {
+ | ---- lifetime `'new` defined here
+LL | v
+ | ^ returning this value requires that `'new` must outlive `'static`
+ |
+ = note: requirement occurs because of the type `RangeMut<'_, (), &()>`, which makes the generic argument `()` invariant
+ = note: the struct `RangeMut<'a, K, V>` is invariant over the parameter `K`
+ = help: see <https://doc.rust-lang.org/nomicon/subtyping.html> for more information about variance
+
+error: lifetime may not live long enough
+ --> $DIR/variance-btree-invariant-types.rs:39:5
+ |
+LL | fn occ_cov_key<'a, 'new>(v: OccupiedEntry<'a, &'static (), ()>)
+ | ---- lifetime `'new` defined here
+LL | -> OccupiedEntry<'a, &'new (), ()> {
+LL | v
+ | ^ returning this value requires that `'new` must outlive `'static`
+ |
+ = note: requirement occurs because of the type `std::collections::btree_map::OccupiedEntry<'_, &(), ()>`, which makes the generic argument `&()` invariant
+ = note: the struct `std::collections::btree_map::OccupiedEntry<'a, K, V, A>` is invariant over the parameter `K`
+ = help: see <https://doc.rust-lang.org/nomicon/subtyping.html> for more information about variance
+
+error: lifetime may not live long enough
+ --> $DIR/variance-btree-invariant-types.rs:44:5
+ |
+LL | fn occ_cov_val<'a, 'new>(v: OccupiedEntry<'a, (), &'static ()>)
+ | ---- lifetime `'new` defined here
+LL | -> OccupiedEntry<'a, (), &'new ()> {
+LL | v
+ | ^ returning this value requires that `'new` must outlive `'static`
+ |
+ = note: requirement occurs because of the type `std::collections::btree_map::OccupiedEntry<'_, (), &()>`, which makes the generic argument `()` invariant
+ = note: the struct `std::collections::btree_map::OccupiedEntry<'a, K, V, A>` is invariant over the parameter `K`
+ = help: see <https://doc.rust-lang.org/nomicon/subtyping.html> for more information about variance
+
+error: lifetime may not live long enough
+ --> $DIR/variance-btree-invariant-types.rs:49:5
+ |
+LL | fn occ_contra_key<'a, 'new>(v: OccupiedEntry<'a, &'new (), ()>)
+ | ---- lifetime `'new` defined here
+LL | -> OccupiedEntry<'a, &'static (), ()> {
+LL | v
+ | ^ returning this value requires that `'new` must outlive `'static`
+ |
+ = note: requirement occurs because of the type `std::collections::btree_map::OccupiedEntry<'_, &(), ()>`, which makes the generic argument `&()` invariant
+ = note: the struct `std::collections::btree_map::OccupiedEntry<'a, K, V, A>` is invariant over the parameter `K`
+ = help: see <https://doc.rust-lang.org/nomicon/subtyping.html> for more information about variance
+
+error: lifetime may not live long enough
+ --> $DIR/variance-btree-invariant-types.rs:54:5
+ |
+LL | fn occ_contra_val<'a, 'new>(v: OccupiedEntry<'a, (), &'new ()>)
+ | ---- lifetime `'new` defined here
+LL | -> OccupiedEntry<'a, (), &'static ()> {
+LL | v
+ | ^ returning this value requires that `'new` must outlive `'static`
+ |
+ = note: requirement occurs because of the type `std::collections::btree_map::OccupiedEntry<'_, (), &()>`, which makes the generic argument `()` invariant
+ = note: the struct `std::collections::btree_map::OccupiedEntry<'a, K, V, A>` is invariant over the parameter `K`
+ = help: see <https://doc.rust-lang.org/nomicon/subtyping.html> for more information about variance
+
+error: lifetime may not live long enough
+ --> $DIR/variance-btree-invariant-types.rs:60:5
+ |
+LL | fn vac_cov_key<'a, 'new>(v: VacantEntry<'a, &'static (), ()>)
+ | ---- lifetime `'new` defined here
+LL | -> VacantEntry<'a, &'new (), ()> {
+LL | v
+ | ^ returning this value requires that `'new` must outlive `'static`
+ |
+ = note: requirement occurs because of the type `std::collections::btree_map::VacantEntry<'_, &(), ()>`, which makes the generic argument `&()` invariant
+ = note: the struct `std::collections::btree_map::VacantEntry<'a, K, V, A>` is invariant over the parameter `K`
+ = help: see <https://doc.rust-lang.org/nomicon/subtyping.html> for more information about variance
+
+error: lifetime may not live long enough
+ --> $DIR/variance-btree-invariant-types.rs:65:5
+ |
+LL | fn vac_cov_val<'a, 'new>(v: VacantEntry<'a, (), &'static ()>)
+ | ---- lifetime `'new` defined here
+LL | -> VacantEntry<'a, (), &'new ()> {
+LL | v
+ | ^ returning this value requires that `'new` must outlive `'static`
+ |
+ = note: requirement occurs because of the type `std::collections::btree_map::VacantEntry<'_, (), &()>`, which makes the generic argument `()` invariant
+ = note: the struct `std::collections::btree_map::VacantEntry<'a, K, V, A>` is invariant over the parameter `K`
+ = help: see <https://doc.rust-lang.org/nomicon/subtyping.html> for more information about variance
+
+error: lifetime may not live long enough
+ --> $DIR/variance-btree-invariant-types.rs:70:5
+ |
+LL | fn vac_contra_key<'a, 'new>(v: VacantEntry<'a, &'new (), ()>)
+ | ---- lifetime `'new` defined here
+LL | -> VacantEntry<'a, &'static (), ()> {
+LL | v
+ | ^ returning this value requires that `'new` must outlive `'static`
+ |
+ = note: requirement occurs because of the type `std::collections::btree_map::VacantEntry<'_, &(), ()>`, which makes the generic argument `&()` invariant
+ = note: the struct `std::collections::btree_map::VacantEntry<'a, K, V, A>` is invariant over the parameter `K`
+ = help: see <https://doc.rust-lang.org/nomicon/subtyping.html> for more information about variance
+
+error: lifetime may not live long enough
+ --> $DIR/variance-btree-invariant-types.rs:75:5
+ |
+LL | fn vac_contra_val<'a, 'new>(v: VacantEntry<'a, (), &'new ()>)
+ | ---- lifetime `'new` defined here
+LL | -> VacantEntry<'a, (), &'static ()> {
+LL | v
+ | ^ returning this value requires that `'new` must outlive `'static`
+ |
+ = note: requirement occurs because of the type `std::collections::btree_map::VacantEntry<'_, (), &()>`, which makes the generic argument `()` invariant
+ = note: the struct `std::collections::btree_map::VacantEntry<'a, K, V, A>` is invariant over the parameter `K`
+ = help: see <https://doc.rust-lang.org/nomicon/subtyping.html> for more information about variance
+
+error: aborting due to 16 previous errors
+
diff --git a/src/test/ui/variance/variance-cell-is-invariant.rs b/src/test/ui/variance/variance-cell-is-invariant.rs
new file mode 100644
index 000000000..62ce4f91f
--- /dev/null
+++ b/src/test/ui/variance/variance-cell-is-invariant.rs
@@ -0,0 +1,19 @@
+// Test that Cell is considered invariant with respect to its
+// type.
+
+use std::cell::Cell;
+
+struct Foo<'a> {
+ x: Cell<Option<&'a isize>>,
+}
+
+fn use_<'short,'long>(c: Foo<'short>,
+ s: &'short isize,
+ l: &'long isize,
+ _where:Option<&'short &'long ()>) {
+ let _: Foo<'long> = c;
+ //~^ ERROR lifetime may not live long enough
+}
+
+fn main() {
+}
diff --git a/src/test/ui/variance/variance-cell-is-invariant.stderr b/src/test/ui/variance/variance-cell-is-invariant.stderr
new file mode 100644
index 000000000..ab5435d16
--- /dev/null
+++ b/src/test/ui/variance/variance-cell-is-invariant.stderr
@@ -0,0 +1,18 @@
+error: lifetime may not live long enough
+ --> $DIR/variance-cell-is-invariant.rs:14:12
+ |
+LL | fn use_<'short,'long>(c: Foo<'short>,
+ | ------ ----- lifetime `'long` defined here
+ | |
+ | lifetime `'short` defined here
+...
+LL | let _: Foo<'long> = c;
+ | ^^^^^^^^^^ type annotation requires that `'short` must outlive `'long`
+ |
+ = help: consider adding the following bound: `'short: 'long`
+ = note: requirement occurs because of the type `Foo<'_>`, which makes the generic argument `'_` invariant
+ = note: the struct `Foo<'a>` is invariant over the parameter `'a`
+ = help: see <https://doc.rust-lang.org/nomicon/subtyping.html> for more information about variance
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/variance/variance-contravariant-arg-object.rs b/src/test/ui/variance/variance-contravariant-arg-object.rs
new file mode 100644
index 000000000..701fcaf69
--- /dev/null
+++ b/src/test/ui/variance/variance-contravariant-arg-object.rs
@@ -0,0 +1,27 @@
+#![allow(dead_code)]
+
+// Test that even when `T` is only used in contravariant position, it
+// is treated as invariant.
+
+trait Get<T> : 'static {
+ fn get(&self, t: T);
+}
+
+fn get_min_from_max<'min, 'max>(v: Box<dyn Get<&'max i32>>)
+ -> Box<dyn Get<&'min i32>>
+ where 'max : 'min
+{
+ v
+ //~^ ERROR lifetime may not live long enough
+}
+
+fn get_max_from_min<'min, 'max>(v: Box<dyn Get<&'min i32>>)
+ -> Box<dyn Get<&'max i32>>
+ where 'max : 'min
+{
+ // Previously OK:
+ v
+ //~^ ERROR lifetime may not live long enough
+}
+
+fn main() { }
diff --git a/src/test/ui/variance/variance-contravariant-arg-object.stderr b/src/test/ui/variance/variance-contravariant-arg-object.stderr
new file mode 100644
index 000000000..ab28315e1
--- /dev/null
+++ b/src/test/ui/variance/variance-contravariant-arg-object.stderr
@@ -0,0 +1,28 @@
+error: lifetime may not live long enough
+ --> $DIR/variance-contravariant-arg-object.rs:14:5
+ |
+LL | fn get_min_from_max<'min, 'max>(v: Box<dyn Get<&'max i32>>)
+ | ---- ---- lifetime `'max` defined here
+ | |
+ | lifetime `'min` defined here
+...
+LL | v
+ | ^ function was supposed to return data with lifetime `'max` but it is returning data with lifetime `'min`
+ |
+ = help: consider adding the following bound: `'min: 'max`
+
+error: lifetime may not live long enough
+ --> $DIR/variance-contravariant-arg-object.rs:23:5
+ |
+LL | fn get_max_from_min<'min, 'max>(v: Box<dyn Get<&'min i32>>)
+ | ---- ---- lifetime `'max` defined here
+ | |
+ | lifetime `'min` defined here
+...
+LL | v
+ | ^ function was supposed to return data with lifetime `'max` but it is returning data with lifetime `'min`
+ |
+ = help: consider adding the following bound: `'min: 'max`
+
+error: aborting due to 2 previous errors
+
diff --git a/src/test/ui/variance/variance-contravariant-arg-trait-match.rs b/src/test/ui/variance/variance-contravariant-arg-trait-match.rs
new file mode 100644
index 000000000..e0b280105
--- /dev/null
+++ b/src/test/ui/variance/variance-contravariant-arg-trait-match.rs
@@ -0,0 +1,28 @@
+#![allow(dead_code)]
+
+// Test that even when `T` is only used in contravariant position, it
+// is treated as invariant.
+
+trait Get<T> {
+ fn get(&self, t: T);
+}
+
+fn get_min_from_max<'min, 'max, G>()
+ where 'max : 'min, G : Get<&'max i32>
+{
+ impls_get::<G,&'min i32>()
+ //~^ ERROR lifetime may not live long enough
+}
+
+fn get_max_from_min<'min, 'max, G>()
+ where 'max : 'min, G : Get<&'min i32>
+{
+ // Previously OK, but now an error because traits are invariant:
+
+ impls_get::<G,&'max i32>()
+ //~^ ERROR lifetime may not live long enough
+}
+
+fn impls_get<G,T>() where G : Get<T> { }
+
+fn main() { }
diff --git a/src/test/ui/variance/variance-contravariant-arg-trait-match.stderr b/src/test/ui/variance/variance-contravariant-arg-trait-match.stderr
new file mode 100644
index 000000000..df9d93907
--- /dev/null
+++ b/src/test/ui/variance/variance-contravariant-arg-trait-match.stderr
@@ -0,0 +1,28 @@
+error: lifetime may not live long enough
+ --> $DIR/variance-contravariant-arg-trait-match.rs:13:5
+ |
+LL | fn get_min_from_max<'min, 'max, G>()
+ | ---- ---- lifetime `'max` defined here
+ | |
+ | lifetime `'min` defined here
+...
+LL | impls_get::<G,&'min i32>()
+ | ^^^^^^^^^^^^^^^^^^^^^^^^ requires that `'min` must outlive `'max`
+ |
+ = help: consider adding the following bound: `'min: 'max`
+
+error: lifetime may not live long enough
+ --> $DIR/variance-contravariant-arg-trait-match.rs:22:5
+ |
+LL | fn get_max_from_min<'min, 'max, G>()
+ | ---- ---- lifetime `'max` defined here
+ | |
+ | lifetime `'min` defined here
+...
+LL | impls_get::<G,&'max i32>()
+ | ^^^^^^^^^^^^^^^^^^^^^^^^ requires that `'min` must outlive `'max`
+ |
+ = help: consider adding the following bound: `'min: 'max`
+
+error: aborting due to 2 previous errors
+
diff --git a/src/test/ui/variance/variance-contravariant-self-trait-match.rs b/src/test/ui/variance/variance-contravariant-self-trait-match.rs
new file mode 100644
index 000000000..8a10554f3
--- /dev/null
+++ b/src/test/ui/variance/variance-contravariant-self-trait-match.rs
@@ -0,0 +1,29 @@
+#![allow(dead_code)]
+
+// Test that even when `Self` is only used in contravariant position, it
+// is treated as invariant.
+
+trait Get {
+ fn get(&self);
+}
+
+fn get_min_from_max<'min, 'max, G>()
+ where 'max : 'min, G : 'max, &'max G : Get
+{
+ impls_get::<&'min G>();
+ //~^ ERROR lifetime may not live long enough
+}
+
+fn get_max_from_min<'min, 'max, G>()
+ where 'max : 'min, G : 'max, &'min G : Get
+{
+ // Previously OK, but now error because traits are invariant with
+ // respect to all inputs.
+
+ impls_get::<&'max G>();
+ //~^ ERROR lifetime may not live long enough
+}
+
+fn impls_get<G>() where G : Get { }
+
+fn main() { }
diff --git a/src/test/ui/variance/variance-contravariant-self-trait-match.stderr b/src/test/ui/variance/variance-contravariant-self-trait-match.stderr
new file mode 100644
index 000000000..bfea1b1b3
--- /dev/null
+++ b/src/test/ui/variance/variance-contravariant-self-trait-match.stderr
@@ -0,0 +1,28 @@
+error: lifetime may not live long enough
+ --> $DIR/variance-contravariant-self-trait-match.rs:13:5
+ |
+LL | fn get_min_from_max<'min, 'max, G>()
+ | ---- ---- lifetime `'max` defined here
+ | |
+ | lifetime `'min` defined here
+...
+LL | impls_get::<&'min G>();
+ | ^^^^^^^^^^^^^^^^^^^^ requires that `'min` must outlive `'max`
+ |
+ = help: consider adding the following bound: `'min: 'max`
+
+error: lifetime may not live long enough
+ --> $DIR/variance-contravariant-self-trait-match.rs:23:5
+ |
+LL | fn get_max_from_min<'min, 'max, G>()
+ | ---- ---- lifetime `'max` defined here
+ | |
+ | lifetime `'min` defined here
+...
+LL | impls_get::<&'max G>();
+ | ^^^^^^^^^^^^^^^^^^^^ requires that `'min` must outlive `'max`
+ |
+ = help: consider adding the following bound: `'min: 'max`
+
+error: aborting due to 2 previous errors
+
diff --git a/src/test/ui/variance/variance-covariant-arg-object.rs b/src/test/ui/variance/variance-covariant-arg-object.rs
new file mode 100644
index 000000000..89cf3117a
--- /dev/null
+++ b/src/test/ui/variance/variance-covariant-arg-object.rs
@@ -0,0 +1,27 @@
+#![allow(dead_code)]
+
+// Test that even when `T` is only used in covariant position, it
+// is treated as invariant.
+
+trait Get<T> : 'static {
+ fn get(&self) -> T;
+}
+
+fn get_min_from_max<'min, 'max>(v: Box<dyn Get<&'max i32>>)
+ -> Box<dyn Get<&'min i32>>
+ where 'max : 'min
+{
+ // Previously OK, now an error as traits are invariant.
+ v
+ //~^ ERROR lifetime may not live long enough
+}
+
+fn get_max_from_min<'min, 'max>(v: Box<dyn Get<&'min i32>>)
+ -> Box<dyn Get<&'max i32>>
+ where 'max : 'min
+{
+ v
+ //~^ ERROR lifetime may not live long enough
+}
+
+fn main() { }
diff --git a/src/test/ui/variance/variance-covariant-arg-object.stderr b/src/test/ui/variance/variance-covariant-arg-object.stderr
new file mode 100644
index 000000000..51f8cb3ec
--- /dev/null
+++ b/src/test/ui/variance/variance-covariant-arg-object.stderr
@@ -0,0 +1,28 @@
+error: lifetime may not live long enough
+ --> $DIR/variance-covariant-arg-object.rs:15:5
+ |
+LL | fn get_min_from_max<'min, 'max>(v: Box<dyn Get<&'max i32>>)
+ | ---- ---- lifetime `'max` defined here
+ | |
+ | lifetime `'min` defined here
+...
+LL | v
+ | ^ function was supposed to return data with lifetime `'max` but it is returning data with lifetime `'min`
+ |
+ = help: consider adding the following bound: `'min: 'max`
+
+error: lifetime may not live long enough
+ --> $DIR/variance-covariant-arg-object.rs:23:5
+ |
+LL | fn get_max_from_min<'min, 'max>(v: Box<dyn Get<&'min i32>>)
+ | ---- ---- lifetime `'max` defined here
+ | |
+ | lifetime `'min` defined here
+...
+LL | v
+ | ^ function was supposed to return data with lifetime `'max` but it is returning data with lifetime `'min`
+ |
+ = help: consider adding the following bound: `'min: 'max`
+
+error: aborting due to 2 previous errors
+
diff --git a/src/test/ui/variance/variance-covariant-arg-trait-match.rs b/src/test/ui/variance/variance-covariant-arg-trait-match.rs
new file mode 100644
index 000000000..68dd449d5
--- /dev/null
+++ b/src/test/ui/variance/variance-covariant-arg-trait-match.rs
@@ -0,0 +1,27 @@
+#![allow(dead_code)]
+
+// Test that even when `T` is only used in covariant position, it
+// is treated as invariant.
+
+trait Get<T> {
+ fn get(&self) -> T;
+}
+
+fn get_min_from_max<'min, 'max, G>()
+ where 'max : 'min, G : Get<&'max i32>
+{
+ // Previously OK, now an error as traits are invariant.
+ impls_get::<G,&'min i32>()
+ //~^ ERROR lifetime may not live long enough
+}
+
+fn get_max_from_min<'min, 'max, G>()
+ where 'max : 'min, G : Get<&'min i32>
+{
+ impls_get::<G,&'max i32>()
+ //~^ ERROR lifetime may not live long enough
+}
+
+fn impls_get<G,T>() where G : Get<T> { }
+
+fn main() { }
diff --git a/src/test/ui/variance/variance-covariant-arg-trait-match.stderr b/src/test/ui/variance/variance-covariant-arg-trait-match.stderr
new file mode 100644
index 000000000..4c7b6cf7c
--- /dev/null
+++ b/src/test/ui/variance/variance-covariant-arg-trait-match.stderr
@@ -0,0 +1,28 @@
+error: lifetime may not live long enough
+ --> $DIR/variance-covariant-arg-trait-match.rs:14:5
+ |
+LL | fn get_min_from_max<'min, 'max, G>()
+ | ---- ---- lifetime `'max` defined here
+ | |
+ | lifetime `'min` defined here
+...
+LL | impls_get::<G,&'min i32>()
+ | ^^^^^^^^^^^^^^^^^^^^^^^^ requires that `'min` must outlive `'max`
+ |
+ = help: consider adding the following bound: `'min: 'max`
+
+error: lifetime may not live long enough
+ --> $DIR/variance-covariant-arg-trait-match.rs:21:5
+ |
+LL | fn get_max_from_min<'min, 'max, G>()
+ | ---- ---- lifetime `'max` defined here
+ | |
+ | lifetime `'min` defined here
+...
+LL | impls_get::<G,&'max i32>()
+ | ^^^^^^^^^^^^^^^^^^^^^^^^ requires that `'min` must outlive `'max`
+ |
+ = help: consider adding the following bound: `'min: 'max`
+
+error: aborting due to 2 previous errors
+
diff --git a/src/test/ui/variance/variance-covariant-self-trait-match.rs b/src/test/ui/variance/variance-covariant-self-trait-match.rs
new file mode 100644
index 000000000..93c25e980
--- /dev/null
+++ b/src/test/ui/variance/variance-covariant-self-trait-match.rs
@@ -0,0 +1,27 @@
+#![allow(dead_code)]
+
+// Test that even when `Self` is only used in covariant position, it
+// is treated as invariant.
+
+trait Get {
+ fn get() -> Self;
+}
+
+fn get_min_from_max<'min, 'max, G>()
+ where 'max : 'min, G : 'max, &'max G : Get
+{
+ // Previously OK, now an error as traits are invariant.
+ impls_get::<&'min G>();
+ //~^ ERROR lifetime may not live long enough
+}
+
+fn get_max_from_min<'min, 'max, G>()
+ where 'max : 'min, G : 'max, &'min G : Get
+{
+ impls_get::<&'max G>();
+ //~^ ERROR lifetime may not live long enough
+}
+
+fn impls_get<G>() where G : Get { }
+
+fn main() { }
diff --git a/src/test/ui/variance/variance-covariant-self-trait-match.stderr b/src/test/ui/variance/variance-covariant-self-trait-match.stderr
new file mode 100644
index 000000000..9b7ba3b66
--- /dev/null
+++ b/src/test/ui/variance/variance-covariant-self-trait-match.stderr
@@ -0,0 +1,28 @@
+error: lifetime may not live long enough
+ --> $DIR/variance-covariant-self-trait-match.rs:14:5
+ |
+LL | fn get_min_from_max<'min, 'max, G>()
+ | ---- ---- lifetime `'max` defined here
+ | |
+ | lifetime `'min` defined here
+...
+LL | impls_get::<&'min G>();
+ | ^^^^^^^^^^^^^^^^^^^^ requires that `'min` must outlive `'max`
+ |
+ = help: consider adding the following bound: `'min: 'max`
+
+error: lifetime may not live long enough
+ --> $DIR/variance-covariant-self-trait-match.rs:21:5
+ |
+LL | fn get_max_from_min<'min, 'max, G>()
+ | ---- ---- lifetime `'max` defined here
+ | |
+ | lifetime `'min` defined here
+...
+LL | impls_get::<&'max G>();
+ | ^^^^^^^^^^^^^^^^^^^^ requires that `'min` must outlive `'max`
+ |
+ = help: consider adding the following bound: `'min: 'max`
+
+error: aborting due to 2 previous errors
+
diff --git a/src/test/ui/variance/variance-invariant-arg-object.rs b/src/test/ui/variance/variance-invariant-arg-object.rs
new file mode 100644
index 000000000..7381b4130
--- /dev/null
+++ b/src/test/ui/variance/variance-invariant-arg-object.rs
@@ -0,0 +1,23 @@
+#![allow(dead_code)]
+
+trait Get<T> : 'static {
+ fn get(&self, t: T) -> T;
+}
+
+fn get_min_from_max<'min, 'max>(v: Box<dyn Get<&'max i32>>)
+ -> Box<dyn Get<&'min i32>>
+ where 'max : 'min
+{
+ v
+ //~^ ERROR lifetime may not live long enough
+}
+
+fn get_max_from_min<'min, 'max>(v: Box<dyn Get<&'min i32>>)
+ -> Box<dyn Get<&'max i32>>
+ where 'max : 'min
+{
+ v
+ //~^ ERROR lifetime may not live long enough
+}
+
+fn main() { }
diff --git a/src/test/ui/variance/variance-invariant-arg-object.stderr b/src/test/ui/variance/variance-invariant-arg-object.stderr
new file mode 100644
index 000000000..9793a36be
--- /dev/null
+++ b/src/test/ui/variance/variance-invariant-arg-object.stderr
@@ -0,0 +1,28 @@
+error: lifetime may not live long enough
+ --> $DIR/variance-invariant-arg-object.rs:11:5
+ |
+LL | fn get_min_from_max<'min, 'max>(v: Box<dyn Get<&'max i32>>)
+ | ---- ---- lifetime `'max` defined here
+ | |
+ | lifetime `'min` defined here
+...
+LL | v
+ | ^ function was supposed to return data with lifetime `'max` but it is returning data with lifetime `'min`
+ |
+ = help: consider adding the following bound: `'min: 'max`
+
+error: lifetime may not live long enough
+ --> $DIR/variance-invariant-arg-object.rs:19:5
+ |
+LL | fn get_max_from_min<'min, 'max>(v: Box<dyn Get<&'min i32>>)
+ | ---- ---- lifetime `'max` defined here
+ | |
+ | lifetime `'min` defined here
+...
+LL | v
+ | ^ function was supposed to return data with lifetime `'max` but it is returning data with lifetime `'min`
+ |
+ = help: consider adding the following bound: `'min: 'max`
+
+error: aborting due to 2 previous errors
+
diff --git a/src/test/ui/variance/variance-invariant-arg-trait-match.rs b/src/test/ui/variance/variance-invariant-arg-trait-match.rs
new file mode 100644
index 000000000..fbcc24387
--- /dev/null
+++ b/src/test/ui/variance/variance-invariant-arg-trait-match.rs
@@ -0,0 +1,23 @@
+#![allow(dead_code)]
+
+trait Get<T> {
+ fn get(&self, t: T) -> T;
+}
+
+fn get_min_from_max<'min, 'max, G>()
+ where 'max : 'min, G : Get<&'max i32>
+{
+ impls_get::<G,&'min i32>()
+ //~^ ERROR lifetime may not live long enough
+}
+
+fn get_max_from_min<'min, 'max, G>()
+ where 'max : 'min, G : Get<&'min i32>
+{
+ impls_get::<G,&'max i32>()
+ //~^ ERROR lifetime may not live long enough
+}
+
+fn impls_get<G,T>() where G : Get<T> { }
+
+fn main() { }
diff --git a/src/test/ui/variance/variance-invariant-arg-trait-match.stderr b/src/test/ui/variance/variance-invariant-arg-trait-match.stderr
new file mode 100644
index 000000000..60ffdd029
--- /dev/null
+++ b/src/test/ui/variance/variance-invariant-arg-trait-match.stderr
@@ -0,0 +1,28 @@
+error: lifetime may not live long enough
+ --> $DIR/variance-invariant-arg-trait-match.rs:10:5
+ |
+LL | fn get_min_from_max<'min, 'max, G>()
+ | ---- ---- lifetime `'max` defined here
+ | |
+ | lifetime `'min` defined here
+...
+LL | impls_get::<G,&'min i32>()
+ | ^^^^^^^^^^^^^^^^^^^^^^^^ requires that `'min` must outlive `'max`
+ |
+ = help: consider adding the following bound: `'min: 'max`
+
+error: lifetime may not live long enough
+ --> $DIR/variance-invariant-arg-trait-match.rs:17:5
+ |
+LL | fn get_max_from_min<'min, 'max, G>()
+ | ---- ---- lifetime `'max` defined here
+ | |
+ | lifetime `'min` defined here
+...
+LL | impls_get::<G,&'max i32>()
+ | ^^^^^^^^^^^^^^^^^^^^^^^^ requires that `'min` must outlive `'max`
+ |
+ = help: consider adding the following bound: `'min: 'max`
+
+error: aborting due to 2 previous errors
+
diff --git a/src/test/ui/variance/variance-invariant-self-trait-match.rs b/src/test/ui/variance/variance-invariant-self-trait-match.rs
new file mode 100644
index 000000000..95c4c2403
--- /dev/null
+++ b/src/test/ui/variance/variance-invariant-self-trait-match.rs
@@ -0,0 +1,23 @@
+#![allow(dead_code)]
+
+trait Get {
+ fn get(&self) -> Self;
+}
+
+fn get_min_from_max<'min, 'max, G>()
+ where 'max : 'min, &'max G : Get, G : 'max
+{
+ impls_get::<&'min G>();
+ //~^ ERROR lifetime may not live long enough
+}
+
+fn get_max_from_min<'min, 'max, G>()
+ where 'max : 'min, &'min G : Get, G : 'min
+{
+ impls_get::<&'max G>();
+ //~^ ERROR lifetime may not live long enough
+}
+
+fn impls_get<G>() where G : Get { }
+
+fn main() { }
diff --git a/src/test/ui/variance/variance-invariant-self-trait-match.stderr b/src/test/ui/variance/variance-invariant-self-trait-match.stderr
new file mode 100644
index 000000000..5b64bd091
--- /dev/null
+++ b/src/test/ui/variance/variance-invariant-self-trait-match.stderr
@@ -0,0 +1,28 @@
+error: lifetime may not live long enough
+ --> $DIR/variance-invariant-self-trait-match.rs:10:5
+ |
+LL | fn get_min_from_max<'min, 'max, G>()
+ | ---- ---- lifetime `'max` defined here
+ | |
+ | lifetime `'min` defined here
+...
+LL | impls_get::<&'min G>();
+ | ^^^^^^^^^^^^^^^^^^^^ requires that `'min` must outlive `'max`
+ |
+ = help: consider adding the following bound: `'min: 'max`
+
+error: lifetime may not live long enough
+ --> $DIR/variance-invariant-self-trait-match.rs:17:5
+ |
+LL | fn get_max_from_min<'min, 'max, G>()
+ | ---- ---- lifetime `'max` defined here
+ | |
+ | lifetime `'min` defined here
+...
+LL | impls_get::<&'max G>();
+ | ^^^^^^^^^^^^^^^^^^^^ requires that `'min` must outlive `'max`
+ |
+ = help: consider adding the following bound: `'min: 'max`
+
+error: aborting due to 2 previous errors
+
diff --git a/src/test/ui/variance/variance-issue-20533.rs b/src/test/ui/variance/variance-issue-20533.rs
new file mode 100644
index 000000000..a2459f873
--- /dev/null
+++ b/src/test/ui/variance/variance-issue-20533.rs
@@ -0,0 +1,43 @@
+// Regression test for issue #20533. At some point, only 1 out of the
+// 3 errors below were being reported.
+
+use std::marker::PhantomData;
+
+fn foo<'a, T>(_x: &'a T) -> PhantomData<&'a ()> {
+ PhantomData
+}
+
+struct Wrap<T>(T);
+
+fn bar<'a, T>(_x: &'a T) -> Wrap<PhantomData<&'a ()>> {
+ Wrap(PhantomData)
+}
+
+struct Baked<'a>(PhantomData<&'a ()>);
+
+fn baz<'a, T>(_x: &'a T) -> Baked<'a> {
+ Baked(PhantomData)
+}
+
+struct AffineU32(u32);
+
+fn main() {
+ {
+ let a = AffineU32(1);
+ let x = foo(&a);
+ drop(a); //~ ERROR cannot move out of `a`
+ drop(x);
+ }
+ {
+ let a = AffineU32(1);
+ let x = bar(&a);
+ drop(a); //~ ERROR cannot move out of `a`
+ drop(x);
+ }
+ {
+ let a = AffineU32(1);
+ let x = baz(&a);
+ drop(a); //~ ERROR cannot move out of `a`
+ drop(x);
+ }
+}
diff --git a/src/test/ui/variance/variance-issue-20533.stderr b/src/test/ui/variance/variance-issue-20533.stderr
new file mode 100644
index 000000000..008e2a002
--- /dev/null
+++ b/src/test/ui/variance/variance-issue-20533.stderr
@@ -0,0 +1,33 @@
+error[E0505]: cannot move out of `a` because it is borrowed
+ --> $DIR/variance-issue-20533.rs:28:14
+ |
+LL | let x = foo(&a);
+ | -- borrow of `a` occurs here
+LL | drop(a);
+ | ^ move out of `a` occurs here
+LL | drop(x);
+ | - borrow later used here
+
+error[E0505]: cannot move out of `a` because it is borrowed
+ --> $DIR/variance-issue-20533.rs:34:14
+ |
+LL | let x = bar(&a);
+ | -- borrow of `a` occurs here
+LL | drop(a);
+ | ^ move out of `a` occurs here
+LL | drop(x);
+ | - borrow later used here
+
+error[E0505]: cannot move out of `a` because it is borrowed
+ --> $DIR/variance-issue-20533.rs:40:14
+ |
+LL | let x = baz(&a);
+ | -- borrow of `a` occurs here
+LL | drop(a);
+ | ^ move out of `a` occurs here
+LL | drop(x);
+ | - borrow later used here
+
+error: aborting due to 3 previous errors
+
+For more information about this error, try `rustc --explain E0505`.
diff --git a/src/test/ui/variance/variance-object-types.rs b/src/test/ui/variance/variance-object-types.rs
new file mode 100644
index 000000000..6ded24cd1
--- /dev/null
+++ b/src/test/ui/variance/variance-object-types.rs
@@ -0,0 +1,12 @@
+#![feature(rustc_attrs)]
+
+
+// For better or worse, associated types are invariant, and hence we
+// get an invariant result for `'a`.
+#[rustc_variance]
+struct Foo<'a> { //~ ERROR [o]
+ x: Box<dyn Fn(i32) -> &'a i32 + 'static>
+}
+
+fn main() {
+}
diff --git a/src/test/ui/variance/variance-object-types.stderr b/src/test/ui/variance/variance-object-types.stderr
new file mode 100644
index 000000000..ceee53aff
--- /dev/null
+++ b/src/test/ui/variance/variance-object-types.stderr
@@ -0,0 +1,8 @@
+error[E0208]: [o]
+ --> $DIR/variance-object-types.rs:7:1
+ |
+LL | struct Foo<'a> {
+ | ^^^^^^^^^^^^^^
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/variance/variance-regions-direct.rs b/src/test/ui/variance/variance-regions-direct.rs
new file mode 100644
index 000000000..3f34e7655
--- /dev/null
+++ b/src/test/ui/variance/variance-regions-direct.rs
@@ -0,0 +1,65 @@
+// Test that we correctly infer variance for region parameters in
+// various self-contained types.
+
+#![feature(rustc_attrs)]
+
+// Regions that just appear in normal spots are contravariant:
+
+#[rustc_variance]
+struct Test2<'a, 'b, 'c> { //~ ERROR [-, -, -]
+ x: &'a isize,
+ y: &'b [isize],
+ c: &'c str
+}
+
+// Those same annotations in function arguments become covariant:
+
+#[rustc_variance]
+struct Test3<'a, 'b, 'c> { //~ ERROR [+, +, +]
+ x: extern "Rust" fn(&'a isize),
+ y: extern "Rust" fn(&'b [isize]),
+ c: extern "Rust" fn(&'c str),
+}
+
+// Mutability induces invariance:
+
+#[rustc_variance]
+struct Test4<'a, 'b:'a> { //~ ERROR [-, o]
+ x: &'a mut &'b isize,
+}
+
+// Mutability induces invariance, even when in a
+// contravariant context:
+
+#[rustc_variance]
+struct Test5<'a, 'b:'a> { //~ ERROR [+, o]
+ x: extern "Rust" fn(&'a mut &'b isize),
+}
+
+// Invariance is a trap from which NO ONE CAN ESCAPE.
+// In other words, even though the `&'b isize` occurs in
+// an argument list (which is contravariant), that
+// argument list occurs in an invariant context.
+
+#[rustc_variance]
+struct Test6<'a, 'b:'a> { //~ ERROR [-, o]
+ x: &'a mut extern "Rust" fn(&'b isize),
+}
+
+// No uses at all is bivariant:
+
+#[rustc_variance]
+struct Test7<'a> { //~ ERROR [*]
+ x: isize
+}
+
+// Try enums too.
+
+#[rustc_variance]
+enum Test8<'a, 'b, 'c:'b> { //~ ERROR [+, -, o]
+ Test8A(extern "Rust" fn(&'a isize)),
+ Test8B(&'b [isize]),
+ Test8C(&'b mut &'c str),
+}
+
+fn main() {}
diff --git a/src/test/ui/variance/variance-regions-direct.stderr b/src/test/ui/variance/variance-regions-direct.stderr
new file mode 100644
index 000000000..25fb22732
--- /dev/null
+++ b/src/test/ui/variance/variance-regions-direct.stderr
@@ -0,0 +1,44 @@
+error[E0208]: [-, -, -]
+ --> $DIR/variance-regions-direct.rs:9:1
+ |
+LL | struct Test2<'a, 'b, 'c> {
+ | ^^^^^^^^^^^^^^^^^^^^^^^^
+
+error[E0208]: [+, +, +]
+ --> $DIR/variance-regions-direct.rs:18:1
+ |
+LL | struct Test3<'a, 'b, 'c> {
+ | ^^^^^^^^^^^^^^^^^^^^^^^^
+
+error[E0208]: [-, o]
+ --> $DIR/variance-regions-direct.rs:27:1
+ |
+LL | struct Test4<'a, 'b:'a> {
+ | ^^^^^^^^^^^^^^^^^^^^^^^
+
+error[E0208]: [+, o]
+ --> $DIR/variance-regions-direct.rs:35:1
+ |
+LL | struct Test5<'a, 'b:'a> {
+ | ^^^^^^^^^^^^^^^^^^^^^^^
+
+error[E0208]: [-, o]
+ --> $DIR/variance-regions-direct.rs:45:1
+ |
+LL | struct Test6<'a, 'b:'a> {
+ | ^^^^^^^^^^^^^^^^^^^^^^^
+
+error[E0208]: [*]
+ --> $DIR/variance-regions-direct.rs:52:1
+ |
+LL | struct Test7<'a> {
+ | ^^^^^^^^^^^^^^^^
+
+error[E0208]: [+, -, o]
+ --> $DIR/variance-regions-direct.rs:59:1
+ |
+LL | enum Test8<'a, 'b, 'c:'b> {
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to 7 previous errors
+
diff --git a/src/test/ui/variance/variance-regions-indirect.rs b/src/test/ui/variance/variance-regions-indirect.rs
new file mode 100644
index 000000000..f84f25ada
--- /dev/null
+++ b/src/test/ui/variance/variance-regions-indirect.rs
@@ -0,0 +1,34 @@
+// Test that we correctly infer variance for region parameters in
+// case that involve multiple intricate types.
+// Try enums too.
+
+#![feature(rustc_attrs)]
+
+#[rustc_variance]
+enum Base<'a, 'b, 'c:'b, 'd> { //~ ERROR [+, -, o, *]
+ Test8A(extern "Rust" fn(&'a isize)),
+ Test8B(&'b [isize]),
+ Test8C(&'b mut &'c str),
+}
+
+#[rustc_variance]
+struct Derived1<'w, 'x:'y, 'y, 'z> { //~ ERROR [*, o, -, +]
+ f: Base<'z, 'y, 'x, 'w>
+}
+
+#[rustc_variance] // Combine - and + to yield o
+struct Derived2<'a, 'b:'a, 'c> { //~ ERROR [o, o, *]
+ f: Base<'a, 'a, 'b, 'c>
+}
+
+#[rustc_variance] // Combine + and o to yield o (just pay attention to 'a here)
+struct Derived3<'a:'b, 'b, 'c> { //~ ERROR [o, -, *]
+ f: Base<'a, 'b, 'a, 'c>
+}
+
+#[rustc_variance] // Combine + and * to yield + (just pay attention to 'a here)
+struct Derived4<'a, 'b, 'c:'b> { //~ ERROR [+, -, o]
+ f: Base<'a, 'b, 'c, 'a>
+}
+
+fn main() {}
diff --git a/src/test/ui/variance/variance-regions-indirect.stderr b/src/test/ui/variance/variance-regions-indirect.stderr
new file mode 100644
index 000000000..fc52492d7
--- /dev/null
+++ b/src/test/ui/variance/variance-regions-indirect.stderr
@@ -0,0 +1,32 @@
+error[E0208]: [+, -, o, *]
+ --> $DIR/variance-regions-indirect.rs:8:1
+ |
+LL | enum Base<'a, 'b, 'c:'b, 'd> {
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error[E0208]: [*, o, -, +]
+ --> $DIR/variance-regions-indirect.rs:15:1
+ |
+LL | struct Derived1<'w, 'x:'y, 'y, 'z> {
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error[E0208]: [o, o, *]
+ --> $DIR/variance-regions-indirect.rs:20:1
+ |
+LL | struct Derived2<'a, 'b:'a, 'c> {
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error[E0208]: [o, -, *]
+ --> $DIR/variance-regions-indirect.rs:25:1
+ |
+LL | struct Derived3<'a:'b, 'b, 'c> {
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error[E0208]: [+, -, o]
+ --> $DIR/variance-regions-indirect.rs:30:1
+ |
+LL | struct Derived4<'a, 'b, 'c:'b> {
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to 5 previous errors
+
diff --git a/src/test/ui/variance/variance-regions-unused-direct.rs b/src/test/ui/variance/variance-regions-unused-direct.rs
new file mode 100644
index 000000000..2afe012bd
--- /dev/null
+++ b/src/test/ui/variance/variance-regions-unused-direct.rs
@@ -0,0 +1,15 @@
+// Test that disallow lifetime parameters that are unused.
+
+use std::marker;
+
+struct Bivariant<'a>; //~ ERROR parameter `'a` is never used
+
+struct Struct<'a, 'd> { //~ ERROR parameter `'d` is never used
+ field: &'a [i32]
+}
+
+trait Trait<'a, 'd> { // OK on traits
+ fn method(&'a self);
+}
+
+fn main() {}
diff --git a/src/test/ui/variance/variance-regions-unused-direct.stderr b/src/test/ui/variance/variance-regions-unused-direct.stderr
new file mode 100644
index 000000000..1a600f5b0
--- /dev/null
+++ b/src/test/ui/variance/variance-regions-unused-direct.stderr
@@ -0,0 +1,19 @@
+error[E0392]: parameter `'a` is never used
+ --> $DIR/variance-regions-unused-direct.rs:5:18
+ |
+LL | struct Bivariant<'a>;
+ | ^^ unused parameter
+ |
+ = help: consider removing `'a`, referring to it in a field, or using a marker such as `PhantomData`
+
+error[E0392]: parameter `'d` is never used
+ --> $DIR/variance-regions-unused-direct.rs:7:19
+ |
+LL | struct Struct<'a, 'd> {
+ | ^^ unused parameter
+ |
+ = help: consider removing `'d`, referring to it in a field, or using a marker such as `PhantomData`
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0392`.
diff --git a/src/test/ui/variance/variance-regions-unused-indirect.rs b/src/test/ui/variance/variance-regions-unused-indirect.rs
new file mode 100644
index 000000000..1514e3956
--- /dev/null
+++ b/src/test/ui/variance/variance-regions-unused-indirect.rs
@@ -0,0 +1,11 @@
+// Test that disallow lifetime parameters that are unused.
+
+enum Foo<'a> { //~ ERROR parameter `'a` is never used
+ Foo1(Bar<'a>)
+}
+
+enum Bar<'a> { //~ ERROR parameter `'a` is never used
+ Bar1(Foo<'a>)
+}
+
+fn main() {}
diff --git a/src/test/ui/variance/variance-regions-unused-indirect.stderr b/src/test/ui/variance/variance-regions-unused-indirect.stderr
new file mode 100644
index 000000000..93710cc13
--- /dev/null
+++ b/src/test/ui/variance/variance-regions-unused-indirect.stderr
@@ -0,0 +1,19 @@
+error[E0392]: parameter `'a` is never used
+ --> $DIR/variance-regions-unused-indirect.rs:3:10
+ |
+LL | enum Foo<'a> {
+ | ^^ unused parameter
+ |
+ = help: consider removing `'a`, referring to it in a field, or using a marker such as `PhantomData`
+
+error[E0392]: parameter `'a` is never used
+ --> $DIR/variance-regions-unused-indirect.rs:7:10
+ |
+LL | enum Bar<'a> {
+ | ^^ unused parameter
+ |
+ = help: consider removing `'a`, referring to it in a field, or using a marker such as `PhantomData`
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0392`.
diff --git a/src/test/ui/variance/variance-trait-bounds.rs b/src/test/ui/variance/variance-trait-bounds.rs
new file mode 100644
index 000000000..ad5334602
--- /dev/null
+++ b/src/test/ui/variance/variance-trait-bounds.rs
@@ -0,0 +1,35 @@
+#![allow(dead_code)]
+#![feature(rustc_attrs)]
+
+// Check that bounds on type parameters (other than `Self`) do not
+// influence variance.
+
+trait Getter<T> {
+ fn get(&self) -> T;
+}
+
+trait Setter<T> {
+ fn get(&self, _: T);
+}
+
+#[rustc_variance]
+struct TestStruct<U,T:Setter<U>> { //~ ERROR [+, +]
+ t: T, u: U
+}
+
+#[rustc_variance]
+enum TestEnum<U,T:Setter<U>> { //~ ERROR [*, +]
+ Foo(T)
+}
+
+#[rustc_variance]
+struct TestContraStruct<U,T:Setter<U>> { //~ ERROR [*, +]
+ t: T
+}
+
+#[rustc_variance]
+struct TestBox<U,T:Getter<U>+Setter<U>> { //~ ERROR [*, +]
+ t: T
+}
+
+pub fn main() { }
diff --git a/src/test/ui/variance/variance-trait-bounds.stderr b/src/test/ui/variance/variance-trait-bounds.stderr
new file mode 100644
index 000000000..e3ef339f4
--- /dev/null
+++ b/src/test/ui/variance/variance-trait-bounds.stderr
@@ -0,0 +1,26 @@
+error[E0208]: [+, +]
+ --> $DIR/variance-trait-bounds.rs:16:1
+ |
+LL | struct TestStruct<U,T:Setter<U>> {
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error[E0208]: [*, +]
+ --> $DIR/variance-trait-bounds.rs:21:1
+ |
+LL | enum TestEnum<U,T:Setter<U>> {
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error[E0208]: [*, +]
+ --> $DIR/variance-trait-bounds.rs:26:1
+ |
+LL | struct TestContraStruct<U,T:Setter<U>> {
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error[E0208]: [*, +]
+ --> $DIR/variance-trait-bounds.rs:31:1
+ |
+LL | struct TestBox<U,T:Getter<U>+Setter<U>> {
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to 4 previous errors
+
diff --git a/src/test/ui/variance/variance-trait-matching.rs b/src/test/ui/variance/variance-trait-matching.rs
new file mode 100644
index 000000000..b4efee7d6
--- /dev/null
+++ b/src/test/ui/variance/variance-trait-matching.rs
@@ -0,0 +1,38 @@
+#![allow(dead_code)]
+
+// Get<T> is covariant in T
+trait Get<T> {
+ fn get(&self) -> T;
+}
+
+struct Cloner<T:Clone> {
+ t: T
+}
+
+impl<T:Clone> Get<T> for Cloner<T> {
+ fn get(&self) -> T {
+ self.t.clone()
+ }
+}
+
+fn get<'a, G>(get: &G) -> i32
+ where G : Get<&'a i32>
+{
+ // This fails to type-check because, without variance, we can't
+ // use `G : Get<&'a i32>` as evidence that `G : Get<&'b i32>`,
+ // even if `'a : 'b`.
+ pick(get, &22) //~ ERROR explicit lifetime required in the type of `get` [E0621]
+}
+
+fn pick<'b, G>(get: &'b G, if_odd: &'b i32) -> i32
+ where G : Get<&'b i32>
+{
+ let v = *get.get();
+ if v % 2 != 0 { v } else { *if_odd }
+}
+
+fn main() {
+ let x = Cloner { t: &23 };
+ let y = get(&x);
+ assert_eq!(y, 23);
+}
diff --git a/src/test/ui/variance/variance-trait-matching.stderr b/src/test/ui/variance/variance-trait-matching.stderr
new file mode 100644
index 000000000..3308cc6d2
--- /dev/null
+++ b/src/test/ui/variance/variance-trait-matching.stderr
@@ -0,0 +1,12 @@
+error[E0621]: explicit lifetime required in the type of `get`
+ --> $DIR/variance-trait-matching.rs:24:5
+ |
+LL | fn get<'a, G>(get: &G) -> i32
+ | -- help: add explicit lifetime `'a` to the type of `get`: `&'a G`
+...
+LL | pick(get, &22)
+ | ^^^^^^^^^^^^^^ lifetime `'a` required
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0621`.
diff --git a/src/test/ui/variance/variance-trait-object-bound.rs b/src/test/ui/variance/variance-trait-object-bound.rs
new file mode 100644
index 000000000..ec3c973bc
--- /dev/null
+++ b/src/test/ui/variance/variance-trait-object-bound.rs
@@ -0,0 +1,18 @@
+// Checks that regions which appear in a trait object type are
+// observed by the variance inference algorithm (and hence
+// `TOption` is contavariant w/r/t `'a` and not bivariant).
+//
+// Issue #18262.
+
+#![feature(rustc_attrs)]
+
+use std::mem;
+
+trait T { fn foo(&self); }
+
+#[rustc_variance]
+struct TOption<'a> { //~ ERROR [-]
+ v: Option<Box<dyn T + 'a>>,
+}
+
+fn main() { }
diff --git a/src/test/ui/variance/variance-trait-object-bound.stderr b/src/test/ui/variance/variance-trait-object-bound.stderr
new file mode 100644
index 000000000..c86cf1f82
--- /dev/null
+++ b/src/test/ui/variance/variance-trait-object-bound.stderr
@@ -0,0 +1,8 @@
+error[E0208]: [-]
+ --> $DIR/variance-trait-object-bound.rs:14:1
+ |
+LL | struct TOption<'a> {
+ | ^^^^^^^^^^^^^^^^^^
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/variance/variance-types-bounds.rs b/src/test/ui/variance/variance-types-bounds.rs
new file mode 100644
index 000000000..d1814dd97
--- /dev/null
+++ b/src/test/ui/variance/variance-types-bounds.rs
@@ -0,0 +1,43 @@
+// Test that we correctly infer variance for type parameters in
+// various types and traits.
+
+#![feature(rustc_attrs)]
+
+#[rustc_variance]
+struct TestImm<A, B> { //~ ERROR [+, +]
+ x: A,
+ y: B,
+}
+
+#[rustc_variance]
+struct TestMut<A, B:'static> { //~ ERROR [+, o]
+ x: A,
+ y: &'static mut B,
+}
+
+#[rustc_variance]
+struct TestIndirect<A:'static, B:'static> { //~ ERROR [+, o]
+ m: TestMut<A, B>
+}
+
+#[rustc_variance]
+struct TestIndirect2<A:'static, B:'static> { //~ ERROR [o, o]
+ n: TestMut<A, B>,
+ m: TestMut<B, A>
+}
+
+trait Getter<A> {
+ fn get(&self) -> A;
+}
+
+trait Setter<A> {
+ fn set(&mut self, a: A);
+}
+
+#[rustc_variance]
+struct TestObject<A, R> { //~ ERROR [o, o]
+ n: Box<dyn Setter<A>+Send>,
+ m: Box<dyn Getter<R>+Send>,
+}
+
+fn main() {}
diff --git a/src/test/ui/variance/variance-types-bounds.stderr b/src/test/ui/variance/variance-types-bounds.stderr
new file mode 100644
index 000000000..dbe8af75d
--- /dev/null
+++ b/src/test/ui/variance/variance-types-bounds.stderr
@@ -0,0 +1,32 @@
+error[E0208]: [+, +]
+ --> $DIR/variance-types-bounds.rs:7:1
+ |
+LL | struct TestImm<A, B> {
+ | ^^^^^^^^^^^^^^^^^^^^
+
+error[E0208]: [+, o]
+ --> $DIR/variance-types-bounds.rs:13:1
+ |
+LL | struct TestMut<A, B:'static> {
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error[E0208]: [+, o]
+ --> $DIR/variance-types-bounds.rs:19:1
+ |
+LL | struct TestIndirect<A:'static, B:'static> {
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error[E0208]: [o, o]
+ --> $DIR/variance-types-bounds.rs:24:1
+ |
+LL | struct TestIndirect2<A:'static, B:'static> {
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error[E0208]: [o, o]
+ --> $DIR/variance-types-bounds.rs:38:1
+ |
+LL | struct TestObject<A, R> {
+ | ^^^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to 5 previous errors
+
diff --git a/src/test/ui/variance/variance-types.rs b/src/test/ui/variance/variance-types.rs
new file mode 100644
index 000000000..b9b6d9c9b
--- /dev/null
+++ b/src/test/ui/variance/variance-types.rs
@@ -0,0 +1,41 @@
+#![allow(dead_code)]
+#![feature(rustc_attrs)]
+
+use std::cell::Cell;
+
+// Check that a type parameter which is only used in a trait bound is
+// not considered bivariant.
+
+#[rustc_variance]
+struct InvariantMut<'a,A:'a,B:'a> { //~ ERROR [-, o, o]
+ t: &'a mut (A,B)
+}
+
+#[rustc_variance]
+struct InvariantCell<A> { //~ ERROR [o]
+ t: Cell<A>
+}
+
+#[rustc_variance]
+struct InvariantIndirect<A> { //~ ERROR [o]
+ t: InvariantCell<A>
+}
+
+#[rustc_variance]
+struct Covariant<A> { //~ ERROR [+]
+ t: A, u: fn() -> A
+}
+
+#[rustc_variance]
+struct Contravariant<A> { //~ ERROR [-]
+ t: fn(A)
+}
+
+#[rustc_variance]
+enum Enum<A,B,C> { //~ ERROR [+, -, o]
+ Foo(Covariant<A>),
+ Bar(Contravariant<B>),
+ Zed(Covariant<C>,Contravariant<C>)
+}
+
+pub fn main() { }
diff --git a/src/test/ui/variance/variance-types.stderr b/src/test/ui/variance/variance-types.stderr
new file mode 100644
index 000000000..8358b18b7
--- /dev/null
+++ b/src/test/ui/variance/variance-types.stderr
@@ -0,0 +1,38 @@
+error[E0208]: [-, o, o]
+ --> $DIR/variance-types.rs:10:1
+ |
+LL | struct InvariantMut<'a,A:'a,B:'a> {
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error[E0208]: [o]
+ --> $DIR/variance-types.rs:15:1
+ |
+LL | struct InvariantCell<A> {
+ | ^^^^^^^^^^^^^^^^^^^^^^^
+
+error[E0208]: [o]
+ --> $DIR/variance-types.rs:20:1
+ |
+LL | struct InvariantIndirect<A> {
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error[E0208]: [+]
+ --> $DIR/variance-types.rs:25:1
+ |
+LL | struct Covariant<A> {
+ | ^^^^^^^^^^^^^^^^^^^
+
+error[E0208]: [-]
+ --> $DIR/variance-types.rs:30:1
+ |
+LL | struct Contravariant<A> {
+ | ^^^^^^^^^^^^^^^^^^^^^^^
+
+error[E0208]: [+, -, o]
+ --> $DIR/variance-types.rs:35:1
+ |
+LL | enum Enum<A,B,C> {
+ | ^^^^^^^^^^^^^^^^
+
+error: aborting due to 6 previous errors
+
diff --git a/src/test/ui/variance/variance-unused-region-param.rs b/src/test/ui/variance/variance-unused-region-param.rs
new file mode 100644
index 000000000..f0e4e03c9
--- /dev/null
+++ b/src/test/ui/variance/variance-unused-region-param.rs
@@ -0,0 +1,7 @@
+// Test that we report an error for unused type parameters in types.
+
+struct SomeStruct<'a> { x: u32 } //~ ERROR parameter `'a` is never used
+enum SomeEnum<'a> { Nothing } //~ ERROR parameter `'a` is never used
+trait SomeTrait<'a> { fn foo(&self); } // OK on traits.
+
+fn main() {}
diff --git a/src/test/ui/variance/variance-unused-region-param.stderr b/src/test/ui/variance/variance-unused-region-param.stderr
new file mode 100644
index 000000000..7c7ec40ba
--- /dev/null
+++ b/src/test/ui/variance/variance-unused-region-param.stderr
@@ -0,0 +1,19 @@
+error[E0392]: parameter `'a` is never used
+ --> $DIR/variance-unused-region-param.rs:3:19
+ |
+LL | struct SomeStruct<'a> { x: u32 }
+ | ^^ unused parameter
+ |
+ = help: consider removing `'a`, referring to it in a field, or using a marker such as `PhantomData`
+
+error[E0392]: parameter `'a` is never used
+ --> $DIR/variance-unused-region-param.rs:4:15
+ |
+LL | enum SomeEnum<'a> { Nothing }
+ | ^^ unused parameter
+ |
+ = help: consider removing `'a`, referring to it in a field, or using a marker such as `PhantomData`
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0392`.
diff --git a/src/test/ui/variance/variance-unused-type-param.rs b/src/test/ui/variance/variance-unused-type-param.rs
new file mode 100644
index 000000000..d11140643
--- /dev/null
+++ b/src/test/ui/variance/variance-unused-type-param.rs
@@ -0,0 +1,28 @@
+#![allow(dead_code)]
+
+// Test that we report an error for unused type parameters in types and traits,
+// and that we offer a helpful suggestion.
+
+struct SomeStruct<A> { x: u32 }
+//~^ ERROR parameter `A` is never used
+
+enum SomeEnum<A> { Nothing }
+//~^ ERROR parameter `A` is never used
+
+// Here T might *appear* used, but in fact it isn't.
+enum ListCell<T> {
+//~^ ERROR parameter `T` is never used
+ Cons(Box<ListCell<T>>),
+ Nil
+}
+
+struct WithBounds<T: Sized> {}
+//~^ ERROR parameter `T` is never used
+
+struct WithWhereBounds<T> where T: Sized {}
+//~^ ERROR parameter `T` is never used
+
+struct WithOutlivesBounds<T: 'static> {}
+//~^ ERROR parameter `T` is never used
+
+fn main() {}
diff --git a/src/test/ui/variance/variance-unused-type-param.stderr b/src/test/ui/variance/variance-unused-type-param.stderr
new file mode 100644
index 000000000..e612da118
--- /dev/null
+++ b/src/test/ui/variance/variance-unused-type-param.stderr
@@ -0,0 +1,54 @@
+error[E0392]: parameter `A` is never used
+ --> $DIR/variance-unused-type-param.rs:6:19
+ |
+LL | struct SomeStruct<A> { x: u32 }
+ | ^ unused parameter
+ |
+ = help: consider removing `A`, referring to it in a field, or using a marker such as `PhantomData`
+ = help: if you intended `A` to be a const parameter, use `const A: usize` instead
+
+error[E0392]: parameter `A` is never used
+ --> $DIR/variance-unused-type-param.rs:9:15
+ |
+LL | enum SomeEnum<A> { Nothing }
+ | ^ unused parameter
+ |
+ = help: consider removing `A`, referring to it in a field, or using a marker such as `PhantomData`
+ = help: if you intended `A` to be a const parameter, use `const A: usize` instead
+
+error[E0392]: parameter `T` is never used
+ --> $DIR/variance-unused-type-param.rs:13:15
+ |
+LL | enum ListCell<T> {
+ | ^ unused parameter
+ |
+ = help: consider removing `T`, referring to it in a field, or using a marker such as `PhantomData`
+ = help: if you intended `T` to be a const parameter, use `const T: usize` instead
+
+error[E0392]: parameter `T` is never used
+ --> $DIR/variance-unused-type-param.rs:19:19
+ |
+LL | struct WithBounds<T: Sized> {}
+ | ^ unused parameter
+ |
+ = help: consider removing `T`, referring to it in a field, or using a marker such as `PhantomData`
+
+error[E0392]: parameter `T` is never used
+ --> $DIR/variance-unused-type-param.rs:22:24
+ |
+LL | struct WithWhereBounds<T> where T: Sized {}
+ | ^ unused parameter
+ |
+ = help: consider removing `T`, referring to it in a field, or using a marker such as `PhantomData`
+
+error[E0392]: parameter `T` is never used
+ --> $DIR/variance-unused-type-param.rs:25:27
+ |
+LL | struct WithOutlivesBounds<T: 'static> {}
+ | ^ unused parameter
+ |
+ = help: consider removing `T`, referring to it in a field, or using a marker such as `PhantomData`
+
+error: aborting due to 6 previous errors
+
+For more information about this error, try `rustc --explain E0392`.
diff --git a/src/test/ui/variance/variance-use-contravariant-struct-1.rs b/src/test/ui/variance/variance-use-contravariant-struct-1.rs
new file mode 100644
index 000000000..7f5906748
--- /dev/null
+++ b/src/test/ui/variance/variance-use-contravariant-struct-1.rs
@@ -0,0 +1,15 @@
+// Test various uses of structs with distint variances to make sure
+// they permit lifetimes to be approximated as expected.
+
+struct SomeStruct<T>(fn(T));
+
+fn foo<'min,'max>(v: SomeStruct<&'max ()>)
+ -> SomeStruct<&'min ()>
+ where 'max : 'min
+{
+ v
+ //~^ ERROR lifetime may not live long enough
+}
+
+
+fn main() { }
diff --git a/src/test/ui/variance/variance-use-contravariant-struct-1.stderr b/src/test/ui/variance/variance-use-contravariant-struct-1.stderr
new file mode 100644
index 000000000..50de7c90f
--- /dev/null
+++ b/src/test/ui/variance/variance-use-contravariant-struct-1.stderr
@@ -0,0 +1,15 @@
+error: lifetime may not live long enough
+ --> $DIR/variance-use-contravariant-struct-1.rs:10:5
+ |
+LL | fn foo<'min,'max>(v: SomeStruct<&'max ()>)
+ | ---- ---- lifetime `'max` defined here
+ | |
+ | lifetime `'min` defined here
+...
+LL | v
+ | ^ function was supposed to return data with lifetime `'max` but it is returning data with lifetime `'min`
+ |
+ = help: consider adding the following bound: `'min: 'max`
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/variance/variance-use-contravariant-struct-2.rs b/src/test/ui/variance/variance-use-contravariant-struct-2.rs
new file mode 100644
index 000000000..2113eb2ad
--- /dev/null
+++ b/src/test/ui/variance/variance-use-contravariant-struct-2.rs
@@ -0,0 +1,17 @@
+// Test various uses of structs with distint variances to make sure
+// they permit lifetimes to be approximated as expected.
+
+#![allow(dead_code)]
+// build-pass (FIXME(62277): could be check-pass?)
+
+struct SomeStruct<T>(fn(T));
+
+fn bar<'min,'max>(v: SomeStruct<&'min ()>)
+ -> SomeStruct<&'max ()>
+ where 'max : 'min
+{
+ v
+}
+
+
+fn main() { }
diff --git a/src/test/ui/variance/variance-use-covariant-struct-1.rs b/src/test/ui/variance/variance-use-covariant-struct-1.rs
new file mode 100644
index 000000000..f0fd7b26e
--- /dev/null
+++ b/src/test/ui/variance/variance-use-covariant-struct-1.rs
@@ -0,0 +1,14 @@
+// Test that a covariant struct does not permit the lifetime of a
+// reference to be enlarged.
+
+struct SomeStruct<T>(T);
+
+fn foo<'min,'max>(v: SomeStruct<&'min ()>)
+ -> SomeStruct<&'max ()>
+ where 'max : 'min
+{
+ v
+ //~^ ERROR lifetime may not live long enough
+}
+
+fn main() { }
diff --git a/src/test/ui/variance/variance-use-covariant-struct-1.stderr b/src/test/ui/variance/variance-use-covariant-struct-1.stderr
new file mode 100644
index 000000000..bab858c5a
--- /dev/null
+++ b/src/test/ui/variance/variance-use-covariant-struct-1.stderr
@@ -0,0 +1,15 @@
+error: lifetime may not live long enough
+ --> $DIR/variance-use-covariant-struct-1.rs:10:5
+ |
+LL | fn foo<'min,'max>(v: SomeStruct<&'min ()>)
+ | ---- ---- lifetime `'max` defined here
+ | |
+ | lifetime `'min` defined here
+...
+LL | v
+ | ^ function was supposed to return data with lifetime `'max` but it is returning data with lifetime `'min`
+ |
+ = help: consider adding the following bound: `'min: 'max`
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/variance/variance-use-covariant-struct-2.rs b/src/test/ui/variance/variance-use-covariant-struct-2.rs
new file mode 100644
index 000000000..ecd2204c9
--- /dev/null
+++ b/src/test/ui/variance/variance-use-covariant-struct-2.rs
@@ -0,0 +1,16 @@
+// Test that a covariant struct permits the lifetime of a reference to
+// be shortened.
+
+#![allow(dead_code)]
+// build-pass (FIXME(62277): could be check-pass?)
+
+struct SomeStruct<T>(T);
+
+fn foo<'min,'max>(v: SomeStruct<&'max ()>)
+ -> SomeStruct<&'min ()>
+ where 'max : 'min
+{
+ v
+}
+
+fn main() { }
diff --git a/src/test/ui/variance/variance-use-invariant-struct-1.rs b/src/test/ui/variance/variance-use-invariant-struct-1.rs
new file mode 100644
index 000000000..d40dbceb5
--- /dev/null
+++ b/src/test/ui/variance/variance-use-invariant-struct-1.rs
@@ -0,0 +1,23 @@
+// Test various uses of structs with distint variances to make sure
+// they permit lifetimes to be approximated as expected.
+
+struct SomeStruct<T>(*mut T);
+
+fn foo<'min,'max>(v: SomeStruct<&'max ()>)
+ -> SomeStruct<&'min ()>
+ where 'max : 'min
+{
+ v
+ //~^ ERROR lifetime may not live long enough
+}
+
+fn bar<'min,'max>(v: SomeStruct<&'min ()>)
+ -> SomeStruct<&'max ()>
+ where 'max : 'min
+{
+ v
+ //~^ ERROR lifetime may not live long enough
+}
+
+
+fn main() { }
diff --git a/src/test/ui/variance/variance-use-invariant-struct-1.stderr b/src/test/ui/variance/variance-use-invariant-struct-1.stderr
new file mode 100644
index 000000000..b9ca6e7d5
--- /dev/null
+++ b/src/test/ui/variance/variance-use-invariant-struct-1.stderr
@@ -0,0 +1,34 @@
+error: lifetime may not live long enough
+ --> $DIR/variance-use-invariant-struct-1.rs:10:5
+ |
+LL | fn foo<'min,'max>(v: SomeStruct<&'max ()>)
+ | ---- ---- lifetime `'max` defined here
+ | |
+ | lifetime `'min` defined here
+...
+LL | v
+ | ^ function was supposed to return data with lifetime `'max` but it is returning data with lifetime `'min`
+ |
+ = help: consider adding the following bound: `'min: 'max`
+ = note: requirement occurs because of the type `SomeStruct<&()>`, which makes the generic argument `&()` invariant
+ = note: the struct `SomeStruct<T>` is invariant over the parameter `T`
+ = help: see <https://doc.rust-lang.org/nomicon/subtyping.html> for more information about variance
+
+error: lifetime may not live long enough
+ --> $DIR/variance-use-invariant-struct-1.rs:18:5
+ |
+LL | fn bar<'min,'max>(v: SomeStruct<&'min ()>)
+ | ---- ---- lifetime `'max` defined here
+ | |
+ | lifetime `'min` defined here
+...
+LL | v
+ | ^ function was supposed to return data with lifetime `'max` but it is returning data with lifetime `'min`
+ |
+ = help: consider adding the following bound: `'min: 'max`
+ = note: requirement occurs because of the type `SomeStruct<&()>`, which makes the generic argument `&()` invariant
+ = note: the struct `SomeStruct<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 2 previous errors
+