about summary refs log tree commit diff
path: root/tests/ui/object-lifetime
diff options
context:
space:
mode:
authorAlbert Larsan <74931857+albertlarsan68@users.noreply.github.com>2023-01-05 09:13:28 +0100
committerAlbert Larsan <74931857+albertlarsan68@users.noreply.github.com>2023-01-11 09:32:08 +0000
commitcf2dff2b1e3fa55fa5415d524200070d0d7aacfe (patch)
tree40a88d9a46aaf3e8870676eb2538378b75a263eb /tests/ui/object-lifetime
parentca855e6e42787ecd062d81d53336fe6788ef51a9 (diff)
downloadrust-cf2dff2b1e3fa55fa5415d524200070d0d7aacfe.tar.gz
rust-cf2dff2b1e3fa55fa5415d524200070d0d7aacfe.zip
Move /src/test to /tests
Diffstat (limited to 'tests/ui/object-lifetime')
-rw-r--r--tests/ui/object-lifetime/object-lifetime-default-ambiguous.rs48
-rw-r--r--tests/ui/object-lifetime/object-lifetime-default-ambiguous.stderr21
-rw-r--r--tests/ui/object-lifetime/object-lifetime-default-default-to-static.rs35
-rw-r--r--tests/ui/object-lifetime/object-lifetime-default-dyn-binding-nonstatic1.rs27
-rw-r--r--tests/ui/object-lifetime/object-lifetime-default-dyn-binding-nonstatic1.stderr9
-rw-r--r--tests/ui/object-lifetime/object-lifetime-default-dyn-binding-nonstatic2.rs30
-rw-r--r--tests/ui/object-lifetime/object-lifetime-default-dyn-binding-nonstatic2.stderr9
-rw-r--r--tests/ui/object-lifetime/object-lifetime-default-dyn-binding-nonstatic3.rs23
-rw-r--r--tests/ui/object-lifetime/object-lifetime-default-dyn-binding-nonstatic3.stderr9
-rw-r--r--tests/ui/object-lifetime/object-lifetime-default-dyn-binding-static.rs28
-rw-r--r--tests/ui/object-lifetime/object-lifetime-default-elision.rs76
-rw-r--r--tests/ui/object-lifetime/object-lifetime-default-elision.stderr15
-rw-r--r--tests/ui/object-lifetime/object-lifetime-default-from-box-error.rs37
-rw-r--r--tests/ui/object-lifetime/object-lifetime-default-from-box-error.stderr33
-rw-r--r--tests/ui/object-lifetime/object-lifetime-default-from-ref-struct.rs58
-rw-r--r--tests/ui/object-lifetime/object-lifetime-default-from-rptr-box-error.rs20
-rw-r--r--tests/ui/object-lifetime/object-lifetime-default-from-rptr-box-error.stderr10
-rw-r--r--tests/ui/object-lifetime/object-lifetime-default-from-rptr-box.rs33
-rw-r--r--tests/ui/object-lifetime/object-lifetime-default-from-rptr-mut.rs36
-rw-r--r--tests/ui/object-lifetime/object-lifetime-default-from-rptr-struct-error.rs25
-rw-r--r--tests/ui/object-lifetime/object-lifetime-default-from-rptr-struct-error.stderr10
-rw-r--r--tests/ui/object-lifetime/object-lifetime-default-from-rptr-struct.rs37
-rw-r--r--tests/ui/object-lifetime/object-lifetime-default-from-rptr.rs42
-rw-r--r--tests/ui/object-lifetime/object-lifetime-default-inferred.rs35
-rw-r--r--tests/ui/object-lifetime/object-lifetime-default-mybox.rs37
-rw-r--r--tests/ui/object-lifetime/object-lifetime-default-mybox.stderr29
-rw-r--r--tests/ui/object-lifetime/object-lifetime-default.rs50
-rw-r--r--tests/ui/object-lifetime/object-lifetime-default.stderr56
28 files changed, 878 insertions, 0 deletions
diff --git a/tests/ui/object-lifetime/object-lifetime-default-ambiguous.rs b/tests/ui/object-lifetime/object-lifetime-default-ambiguous.rs
new file mode 100644
index 00000000000..5dae92fee5f
--- /dev/null
+++ b/tests/ui/object-lifetime/object-lifetime-default-ambiguous.rs
@@ -0,0 +1,48 @@
+// Test that if a struct declares multiple region bounds for a given
+// type parameter, an explicit lifetime bound is required on object
+// lifetimes within.
+
+#![allow(dead_code)]
+
+trait Test {
+    fn foo(&self) { }
+}
+
+struct Ref0<T:?Sized> {
+    r: *mut T
+}
+
+struct Ref1<'a,T:'a+?Sized> {
+    r: &'a T
+}
+
+struct Ref2<'a,'b:'a,T:'a+'b+?Sized> {
+    r: &'a &'b T
+}
+
+fn a<'a,'b>(t: Ref2<'a,'b, dyn Test>) {
+    //~^ ERROR lifetime bound for this object type cannot be deduced from context
+}
+
+fn b(t: Ref2<dyn Test>) {
+    //~^ ERROR lifetime bound for this object type cannot be deduced from context
+}
+
+fn c(t: Ref2<&dyn Test>) {
+    // In this case, the &'a overrides.
+}
+
+fn d(t: Ref2<Ref1<dyn Test>>) {
+    // In this case, the lifetime parameter from the Ref1 overrides.
+}
+
+fn e(t: Ref2<Ref0<dyn Test>>) {
+    // In this case, Ref2 is ambiguous, but Ref0 overrides with 'static.
+}
+
+fn f(t: &Ref2<dyn Test>) {
+    //~^ ERROR lifetime bound for this object type cannot be deduced from context
+}
+
+fn main() {
+}
diff --git a/tests/ui/object-lifetime/object-lifetime-default-ambiguous.stderr b/tests/ui/object-lifetime/object-lifetime-default-ambiguous.stderr
new file mode 100644
index 00000000000..bd50a27fd5e
--- /dev/null
+++ b/tests/ui/object-lifetime/object-lifetime-default-ambiguous.stderr
@@ -0,0 +1,21 @@
+error[E0228]: the lifetime bound for this object type cannot be deduced from context; please supply an explicit bound
+  --> $DIR/object-lifetime-default-ambiguous.rs:23:28
+   |
+LL | fn a<'a,'b>(t: Ref2<'a,'b, dyn Test>) {
+   |                            ^^^^^^^^
+
+error[E0228]: the lifetime bound for this object type cannot be deduced from context; please supply an explicit bound
+  --> $DIR/object-lifetime-default-ambiguous.rs:27:14
+   |
+LL | fn b(t: Ref2<dyn Test>) {
+   |              ^^^^^^^^
+
+error[E0228]: the lifetime bound for this object type cannot be deduced from context; please supply an explicit bound
+  --> $DIR/object-lifetime-default-ambiguous.rs:43:15
+   |
+LL | fn f(t: &Ref2<dyn Test>) {
+   |               ^^^^^^^^
+
+error: aborting due to 3 previous errors
+
+For more information about this error, try `rustc --explain E0228`.
diff --git a/tests/ui/object-lifetime/object-lifetime-default-default-to-static.rs b/tests/ui/object-lifetime/object-lifetime-default-default-to-static.rs
new file mode 100644
index 00000000000..467767ae59d
--- /dev/null
+++ b/tests/ui/object-lifetime/object-lifetime-default-default-to-static.rs
@@ -0,0 +1,35 @@
+// run-pass
+// Test that `Box<Test>` is equivalent to `Box<Test+'static>`, both in
+// fields and fn arguments.
+
+// pretty-expanded FIXME #23616
+
+#![allow(dead_code)]
+
+trait Test {
+    fn foo(&self) { }
+}
+
+struct SomeStruct {
+    t: Box<dyn Test>,
+    u: Box<dyn Test+'static>,
+}
+
+fn a(t: Box<dyn Test>, mut ss: SomeStruct) {
+    ss.t = t;
+}
+
+fn b(t: Box<dyn Test+'static>, mut ss: SomeStruct) {
+    ss.t = t;
+}
+
+fn c(t: Box<dyn Test>, mut ss: SomeStruct) {
+    ss.u = t;
+}
+
+fn d(t: Box<dyn Test+'static>, mut ss: SomeStruct) {
+    ss.u = t;
+}
+
+fn main() {
+}
diff --git a/tests/ui/object-lifetime/object-lifetime-default-dyn-binding-nonstatic1.rs b/tests/ui/object-lifetime/object-lifetime-default-dyn-binding-nonstatic1.rs
new file mode 100644
index 00000000000..7337383e297
--- /dev/null
+++ b/tests/ui/object-lifetime/object-lifetime-default-dyn-binding-nonstatic1.rs
@@ -0,0 +1,27 @@
+// Test that `dyn Bar<Item = XX>` uses `'static` as the default object
+// lifetime bound for the type `XX`.
+
+trait Foo<'a> {
+    type Item: ?Sized;
+
+    fn item(&self) -> Box<Self::Item> { panic!() }
+}
+
+trait Bar { }
+
+impl<T> Foo<'_> for T {
+    type Item = dyn Bar;
+}
+
+fn is_static<T>(_: T) where T: 'static { }
+
+// Here, we should default to `dyn Bar + 'static`, but the current
+// code forces us into a conservative, hacky path.
+fn bar<'a>(x: &'a str) -> &'a dyn Foo<'a, Item = dyn Bar> { &() }
+//~^ ERROR please supply an explicit bound
+
+fn main() {
+    let s = format!("foo");
+    let r = bar(&s);
+    is_static(r.item());
+}
diff --git a/tests/ui/object-lifetime/object-lifetime-default-dyn-binding-nonstatic1.stderr b/tests/ui/object-lifetime/object-lifetime-default-dyn-binding-nonstatic1.stderr
new file mode 100644
index 00000000000..f06a9da1dee
--- /dev/null
+++ b/tests/ui/object-lifetime/object-lifetime-default-dyn-binding-nonstatic1.stderr
@@ -0,0 +1,9 @@
+error[E0228]: the lifetime bound for this object type cannot be deduced from context; please supply an explicit bound
+  --> $DIR/object-lifetime-default-dyn-binding-nonstatic1.rs:20:50
+   |
+LL | fn bar<'a>(x: &'a str) -> &'a dyn Foo<'a, Item = dyn Bar> { &() }
+   |                                                  ^^^^^^^
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0228`.
diff --git a/tests/ui/object-lifetime/object-lifetime-default-dyn-binding-nonstatic2.rs b/tests/ui/object-lifetime/object-lifetime-default-dyn-binding-nonstatic2.rs
new file mode 100644
index 00000000000..2a7415174f8
--- /dev/null
+++ b/tests/ui/object-lifetime/object-lifetime-default-dyn-binding-nonstatic2.rs
@@ -0,0 +1,30 @@
+// Test that `dyn Bar<Item = XX>` uses `'static` as the default object
+// lifetime bound for the type `XX`.
+
+trait Foo<'a> {
+    type Item: 'a + ?Sized;
+
+    fn item(&self) -> Box<Self::Item> { panic!() }
+}
+
+trait Bar { }
+
+impl<T> Foo<'_> for T {
+    type Item = dyn Bar;
+}
+
+fn is_static<T>(_: T) where T: 'static { }
+
+// Here, we default to `dyn Bar + 'a`.  Or, we *should*, but the
+// current code forces us into a conservative, hacky path.
+fn bar<'a>(x: &'a str) -> &'a dyn Foo<'a, Item = dyn Bar> { &() }
+//~^ ERROR please supply an explicit bound
+
+fn main() {
+    let s = format!("foo");
+    let r = bar(&s);
+
+    // If it weren't for the conservative path above, we'd expect an
+    // error here.
+    is_static(r.item());
+}
diff --git a/tests/ui/object-lifetime/object-lifetime-default-dyn-binding-nonstatic2.stderr b/tests/ui/object-lifetime/object-lifetime-default-dyn-binding-nonstatic2.stderr
new file mode 100644
index 00000000000..51d8450af76
--- /dev/null
+++ b/tests/ui/object-lifetime/object-lifetime-default-dyn-binding-nonstatic2.stderr
@@ -0,0 +1,9 @@
+error[E0228]: the lifetime bound for this object type cannot be deduced from context; please supply an explicit bound
+  --> $DIR/object-lifetime-default-dyn-binding-nonstatic2.rs:20:50
+   |
+LL | fn bar<'a>(x: &'a str) -> &'a dyn Foo<'a, Item = dyn Bar> { &() }
+   |                                                  ^^^^^^^
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0228`.
diff --git a/tests/ui/object-lifetime/object-lifetime-default-dyn-binding-nonstatic3.rs b/tests/ui/object-lifetime/object-lifetime-default-dyn-binding-nonstatic3.rs
new file mode 100644
index 00000000000..51be999a632
--- /dev/null
+++ b/tests/ui/object-lifetime/object-lifetime-default-dyn-binding-nonstatic3.rs
@@ -0,0 +1,23 @@
+// Test that `dyn Bar<Item = XX>` uses `'static` as the default object
+// lifetime bound for the type `XX`.
+
+trait Foo<'a> {
+    type Item: ?Sized;
+
+    fn item(&self) -> Box<Self::Item> { panic!() }
+}
+
+trait Bar { }
+
+fn is_static<T>(_: T) where T: 'static { }
+
+// Here, we should default to `dyn Bar + 'static`, but the current
+// code forces us into a conservative, hacky path.
+fn bar(x: &str) -> &dyn Foo<Item = dyn Bar> { &() }
+//~^ ERROR please supply an explicit bound
+
+fn main() {
+    let s = format!("foo");
+    let r = bar(&s);
+    is_static(r.item());
+}
diff --git a/tests/ui/object-lifetime/object-lifetime-default-dyn-binding-nonstatic3.stderr b/tests/ui/object-lifetime/object-lifetime-default-dyn-binding-nonstatic3.stderr
new file mode 100644
index 00000000000..f721bf39419
--- /dev/null
+++ b/tests/ui/object-lifetime/object-lifetime-default-dyn-binding-nonstatic3.stderr
@@ -0,0 +1,9 @@
+error[E0228]: the lifetime bound for this object type cannot be deduced from context; please supply an explicit bound
+  --> $DIR/object-lifetime-default-dyn-binding-nonstatic3.rs:16:36
+   |
+LL | fn bar(x: &str) -> &dyn Foo<Item = dyn Bar> { &() }
+   |                                    ^^^^^^^
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0228`.
diff --git a/tests/ui/object-lifetime/object-lifetime-default-dyn-binding-static.rs b/tests/ui/object-lifetime/object-lifetime-default-dyn-binding-static.rs
new file mode 100644
index 00000000000..339f3356bd7
--- /dev/null
+++ b/tests/ui/object-lifetime/object-lifetime-default-dyn-binding-static.rs
@@ -0,0 +1,28 @@
+// Test that `dyn Bar<Item = XX>` uses `'static` as the default object
+// lifetime bound for the type `XX`.
+//
+// check-pass
+
+trait Foo {
+    type Item: ?Sized;
+
+    fn item(&self) -> Box<Self::Item> { panic!() }
+}
+
+trait Bar { }
+
+impl<T> Foo for T {
+    type Item = dyn Bar;
+}
+
+fn is_static<T>(_: T) where T: 'static { }
+
+// Here, we default to `dyn Bar + 'static`, and not `&'x dyn Foo<Item
+// = dyn Bar + 'x>`.
+fn bar(x: &str) -> &dyn Foo<Item = dyn Bar> { &() }
+
+fn main() {
+    let s = format!("foo");
+    let r = bar(&s);
+    is_static(r.item());
+}
diff --git a/tests/ui/object-lifetime/object-lifetime-default-elision.rs b/tests/ui/object-lifetime/object-lifetime-default-elision.rs
new file mode 100644
index 00000000000..f7c0261cfbb
--- /dev/null
+++ b/tests/ui/object-lifetime/object-lifetime-default-elision.rs
@@ -0,0 +1,76 @@
+// Test various cases where the old rules under lifetime elision
+// yield slightly different results than the new rules.
+
+#![allow(dead_code)]
+
+trait SomeTrait {
+    fn dummy(&self) { }
+}
+
+struct SomeStruct<'a> {
+    r: Box<dyn SomeTrait+'a>
+}
+
+fn deref<T>(ss: &T) -> T {
+    // produces the type of a deref without worrying about whether a
+    // move out would actually be legal
+    loop { }
+}
+
+fn load0<'a>(ss: &'a Box<dyn SomeTrait>) -> Box<dyn SomeTrait> {
+    // Under old rules, the fully elaborated types of input/output were:
+    //
+    // for<'a,'b> fn(&'a Box<SomeTrait+'b>) -> Box<SomeTrait+'a>
+    //
+    // Under new rules the result is:
+    //
+    // for<'a> fn(&'a Box<SomeTrait+'static>) -> Box<SomeTrait+'static>
+    //
+    // Therefore, no type error.
+
+    deref(ss)
+}
+
+fn load1(ss: &dyn SomeTrait) -> &dyn SomeTrait {
+    // Under old rules, the fully elaborated types of input/output were:
+    //
+    // for<'a,'b> fn(&'a (SomeTrait+'b)) -> &'a (SomeTrait+'a)
+    //
+    // Under new rules the result is:
+    //
+    // for<'a> fn(&'a (SomeTrait+'a)) -> &'a (SomeTrait+'a)
+    //
+    // In both cases, returning `ss` is legal.
+
+    ss
+}
+
+fn load2<'a>(ss: &'a dyn SomeTrait) -> &dyn SomeTrait {
+    // Same as `load1` but with an explicit name thrown in for fun.
+
+    ss
+}
+
+fn load3<'a,'b>(ss: &'a dyn SomeTrait) -> &'b dyn SomeTrait {
+    // Under old rules, the fully elaborated types of input/output were:
+    //
+    // for<'a,'b,'c>fn(&'a (SomeTrait+'c)) -> &'b (SomeTrait+'a)
+    //
+    // Based on the input/output types, the compiler could infer that
+    //     'c : 'a
+    //     'b : 'a
+    // must hold, and therefore it permitted `&'a (Sometrait+'c)` to be
+    // coerced to `&'b (SomeTrait+'a)`.
+    //
+    // Under the newer defaults, though, we get:
+    //
+    // for<'a,'b> fn(&'a (SomeTrait+'a)) -> &'b (SomeTrait+'b)
+    //
+    // which fails to type check.
+
+    ss
+        //~^ ERROR lifetime may not live long enough
+}
+
+fn main() {
+}
diff --git a/tests/ui/object-lifetime/object-lifetime-default-elision.stderr b/tests/ui/object-lifetime/object-lifetime-default-elision.stderr
new file mode 100644
index 00000000000..61e96f59fed
--- /dev/null
+++ b/tests/ui/object-lifetime/object-lifetime-default-elision.stderr
@@ -0,0 +1,15 @@
+error: lifetime may not live long enough
+  --> $DIR/object-lifetime-default-elision.rs:71:5
+   |
+LL | fn load3<'a,'b>(ss: &'a dyn SomeTrait) -> &'b dyn SomeTrait {
+   |          -- -- lifetime `'b` defined here
+   |          |
+   |          lifetime `'a` defined here
+...
+LL |     ss
+   |     ^^ function was supposed to return data with lifetime `'b` but it is returning data with lifetime `'a`
+   |
+   = help: consider adding the following bound: `'a: 'b`
+
+error: aborting due to previous error
+
diff --git a/tests/ui/object-lifetime/object-lifetime-default-from-box-error.rs b/tests/ui/object-lifetime/object-lifetime-default-from-box-error.rs
new file mode 100644
index 00000000000..f9b3e2238d3
--- /dev/null
+++ b/tests/ui/object-lifetime/object-lifetime-default-from-box-error.rs
@@ -0,0 +1,37 @@
+// Test various cases where the defaults should lead to errors being
+// reported.
+
+#![allow(dead_code)]
+
+trait SomeTrait {
+    fn dummy(&self) { }
+}
+
+struct SomeStruct<'a> {
+    r: Box<dyn SomeTrait+'a>
+}
+
+fn load(ss: &mut SomeStruct) -> Box<dyn SomeTrait> {
+    // `Box<SomeTrait>` defaults to a `'static` bound, so this return
+    // is illegal.
+
+    ss.r
+    //~^ ERROR lifetime may not live long enough
+    //~| ERROR cannot move out of
+}
+
+fn store(ss: &mut SomeStruct, b: Box<dyn SomeTrait>) {
+    // No error: b is bounded by 'static which outlives the
+    // (anonymous) lifetime on the struct.
+
+    ss.r = b;
+}
+
+fn store1<'b>(ss: &mut SomeStruct, b: Box<dyn SomeTrait+'b>) {
+    // Here we override the lifetimes explicitly, and so naturally we get an error.
+
+    ss.r = b; //~ ERROR explicit lifetime required in the type of `ss` [E0621]
+}
+
+fn main() {
+}
diff --git a/tests/ui/object-lifetime/object-lifetime-default-from-box-error.stderr b/tests/ui/object-lifetime/object-lifetime-default-from-box-error.stderr
new file mode 100644
index 00000000000..15b36925c47
--- /dev/null
+++ b/tests/ui/object-lifetime/object-lifetime-default-from-box-error.stderr
@@ -0,0 +1,33 @@
+error: lifetime may not live long enough
+  --> $DIR/object-lifetime-default-from-box-error.rs:18:5
+   |
+LL | fn load(ss: &mut SomeStruct) -> Box<dyn SomeTrait> {
+   |         -- has type `&mut SomeStruct<'1>`
+...
+LL |     ss.r
+   |     ^^^^ returning this value requires that `'1` must outlive `'static`
+   |
+help: to declare that the trait object captures data from argument `ss`, you can add an explicit `'_` lifetime bound
+   |
+LL | fn load(ss: &mut SomeStruct) -> Box<dyn SomeTrait + '_> {
+   |                                                   ++++
+
+error[E0507]: cannot move out of `ss.r` which is behind a mutable reference
+  --> $DIR/object-lifetime-default-from-box-error.rs:18:5
+   |
+LL |     ss.r
+   |     ^^^^ move occurs because `ss.r` has type `Box<dyn SomeTrait>`, which does not implement the `Copy` trait
+
+error[E0621]: explicit lifetime required in the type of `ss`
+  --> $DIR/object-lifetime-default-from-box-error.rs:33:5
+   |
+LL | fn store1<'b>(ss: &mut SomeStruct, b: Box<dyn SomeTrait+'b>) {
+   |                   --------------- help: add explicit lifetime `'b` to the type of `ss`: `&mut SomeStruct<'b>`
+...
+LL |     ss.r = b;
+   |     ^^^^ lifetime `'b` required
+
+error: aborting due to 3 previous errors
+
+Some errors have detailed explanations: E0507, E0621.
+For more information about an error, try `rustc --explain E0507`.
diff --git a/tests/ui/object-lifetime/object-lifetime-default-from-ref-struct.rs b/tests/ui/object-lifetime/object-lifetime-default-from-ref-struct.rs
new file mode 100644
index 00000000000..e1a865fa503
--- /dev/null
+++ b/tests/ui/object-lifetime/object-lifetime-default-from-ref-struct.rs
@@ -0,0 +1,58 @@
+// run-pass
+// Test that the lifetime of the enclosing `&` is used for the object
+// lifetime bound.
+
+// pretty-expanded FIXME #23616
+
+#![allow(dead_code)]
+
+use std::fmt::Display;
+
+trait Test {
+    fn foo(&self) { }
+}
+
+struct Ref<'a,T:'a+?Sized> {
+    r: &'a T
+}
+
+struct Ref2<'a,'b,T:'a+'b+?Sized> {
+    a: &'a T,
+    b: &'b T
+}
+
+struct SomeStruct<'a> {
+    t: Ref<'a, dyn Test>,
+    u: Ref<'a, dyn Test+'a>,
+}
+
+fn a<'a>(t: Ref<'a, dyn Test>, mut ss: SomeStruct<'a>) {
+    ss.t = t;
+}
+
+fn b<'a>(t: Ref<'a, dyn Test>, mut ss: SomeStruct<'a>) {
+    ss.u = t;
+}
+
+fn c<'a>(t: Ref<'a, dyn Test+'a>, mut ss: SomeStruct<'a>) {
+    ss.t = t;
+}
+
+fn d<'a>(t: Ref<'a, dyn Test+'a>, mut ss: SomeStruct<'a>) {
+    ss.u = t;
+}
+
+fn e<'a>(_: Ref<'a, dyn Display+'static>) {}
+fn g<'a, 'b>(_: Ref2<'a, 'b, dyn Display+'static>) {}
+
+
+fn main() {
+    // Inside a function body, we can just infer all
+    // lifetimes, to allow Ref<'tmp, Display+'static>
+    // and Ref2<'tmp, 'tmp, Display+'static>.
+    let x = &0 as &(dyn Display+'static);
+    let r: Ref<dyn Display> = Ref { r: x };
+    let r2: Ref2<dyn Display> = Ref2 { a: x, b: x };
+    e(r);
+    g(r2);
+}
diff --git a/tests/ui/object-lifetime/object-lifetime-default-from-rptr-box-error.rs b/tests/ui/object-lifetime/object-lifetime-default-from-rptr-box-error.rs
new file mode 100644
index 00000000000..de79eee6a7d
--- /dev/null
+++ b/tests/ui/object-lifetime/object-lifetime-default-from-rptr-box-error.rs
@@ -0,0 +1,20 @@
+// Test that the lifetime from the enclosing `&` is "inherited"
+// through the `Box` struct.
+
+#![allow(dead_code)]
+
+trait Test {
+    fn foo(&self) { }
+}
+
+struct SomeStruct<'a> {
+    t: &'a Box<dyn Test>,
+}
+
+fn c<'a>(t: &'a Box<dyn Test+'a>, mut ss: SomeStruct<'a>) {
+    ss.t = t;
+    //~^ ERROR lifetime may not live long enough
+}
+
+fn main() {
+}
diff --git a/tests/ui/object-lifetime/object-lifetime-default-from-rptr-box-error.stderr b/tests/ui/object-lifetime/object-lifetime-default-from-rptr-box-error.stderr
new file mode 100644
index 00000000000..7d6f9f39d13
--- /dev/null
+++ b/tests/ui/object-lifetime/object-lifetime-default-from-rptr-box-error.stderr
@@ -0,0 +1,10 @@
+error: lifetime may not live long enough
+  --> $DIR/object-lifetime-default-from-rptr-box-error.rs:15:5
+   |
+LL | fn c<'a>(t: &'a Box<dyn Test+'a>, mut ss: SomeStruct<'a>) {
+   |      -- lifetime `'a` defined here
+LL |     ss.t = t;
+   |     ^^^^^^^^ assignment requires that `'a` must outlive `'static`
+
+error: aborting due to previous error
+
diff --git a/tests/ui/object-lifetime/object-lifetime-default-from-rptr-box.rs b/tests/ui/object-lifetime/object-lifetime-default-from-rptr-box.rs
new file mode 100644
index 00000000000..b61083078cc
--- /dev/null
+++ b/tests/ui/object-lifetime/object-lifetime-default-from-rptr-box.rs
@@ -0,0 +1,33 @@
+// run-pass
+// Test that the lifetime from the enclosing `&` is "inherited"
+// through the `Box` struct.
+
+// pretty-expanded FIXME #23616
+
+#![allow(dead_code)]
+
+trait Test {
+    fn foo(&self) { }
+}
+
+struct SomeStruct<'a> {
+    t: &'a Box<dyn Test>,
+    u: &'a Box<dyn Test+'a>,
+}
+
+fn a<'a>(t: &'a Box<dyn Test>, mut ss: SomeStruct<'a>) {
+    ss.t = t;
+}
+
+fn b<'a>(t: &'a Box<dyn Test>, mut ss: SomeStruct<'a>) {
+    ss.u = t;
+}
+
+// see also ui/object-lifetime/object-lifetime-default-from-rptr-box-error.rs
+
+fn d<'a>(t: &'a Box<dyn Test+'a>, mut ss: SomeStruct<'a>) {
+    ss.u = t;
+}
+
+fn main() {
+}
diff --git a/tests/ui/object-lifetime/object-lifetime-default-from-rptr-mut.rs b/tests/ui/object-lifetime/object-lifetime-default-from-rptr-mut.rs
new file mode 100644
index 00000000000..a09fc03ab9b
--- /dev/null
+++ b/tests/ui/object-lifetime/object-lifetime-default-from-rptr-mut.rs
@@ -0,0 +1,36 @@
+// run-pass
+// Test that the lifetime of the enclosing `&` is used for the object
+// lifetime bound.
+
+// pretty-expanded FIXME #23616
+
+#![allow(dead_code)]
+
+trait Test {
+    fn foo(&self) { }
+}
+
+struct SomeStruct<'a> {
+    t: &'a mut dyn Test,
+    u: &'a mut (dyn Test+'a),
+}
+
+fn a<'a>(t: &'a mut dyn Test, mut ss: SomeStruct<'a>) {
+    ss.t = t;
+}
+
+fn b<'a>(t: &'a mut dyn Test, mut ss: SomeStruct<'a>) {
+    ss.u = t;
+}
+
+fn c<'a>(t: &'a mut (dyn Test+'a), mut ss: SomeStruct<'a>) {
+    ss.t = t;
+}
+
+fn d<'a>(t: &'a mut (dyn Test+'a), mut ss: SomeStruct<'a>) {
+    ss.u = t;
+}
+
+
+fn main() {
+}
diff --git a/tests/ui/object-lifetime/object-lifetime-default-from-rptr-struct-error.rs b/tests/ui/object-lifetime/object-lifetime-default-from-rptr-struct-error.rs
new file mode 100644
index 00000000000..877486e1557
--- /dev/null
+++ b/tests/ui/object-lifetime/object-lifetime-default-from-rptr-struct-error.rs
@@ -0,0 +1,25 @@
+// Test that the lifetime from the enclosing `&` is "inherited"
+// through the `MyBox` struct.
+
+#![allow(dead_code)]
+
+trait Test {
+    fn foo(&self) { }
+}
+
+struct SomeStruct<'a> {
+    t: &'a MyBox<dyn Test>,
+    u: &'a MyBox<dyn Test + 'a>,
+}
+
+struct MyBox<T:?Sized> {
+    b: Box<T>
+}
+
+fn c<'a>(t: &'a MyBox<dyn Test+'a>, mut ss: SomeStruct<'a>) {
+    ss.t = t;
+    //~^ ERROR lifetime may not live long enough
+}
+
+fn main() {
+}
diff --git a/tests/ui/object-lifetime/object-lifetime-default-from-rptr-struct-error.stderr b/tests/ui/object-lifetime/object-lifetime-default-from-rptr-struct-error.stderr
new file mode 100644
index 00000000000..2bc8e097859
--- /dev/null
+++ b/tests/ui/object-lifetime/object-lifetime-default-from-rptr-struct-error.stderr
@@ -0,0 +1,10 @@
+error: lifetime may not live long enough
+  --> $DIR/object-lifetime-default-from-rptr-struct-error.rs:20:5
+   |
+LL | fn c<'a>(t: &'a MyBox<dyn Test+'a>, mut ss: SomeStruct<'a>) {
+   |      -- lifetime `'a` defined here
+LL |     ss.t = t;
+   |     ^^^^^^^^ assignment requires that `'a` must outlive `'static`
+
+error: aborting due to previous error
+
diff --git a/tests/ui/object-lifetime/object-lifetime-default-from-rptr-struct.rs b/tests/ui/object-lifetime/object-lifetime-default-from-rptr-struct.rs
new file mode 100644
index 00000000000..d3e92e16246
--- /dev/null
+++ b/tests/ui/object-lifetime/object-lifetime-default-from-rptr-struct.rs
@@ -0,0 +1,37 @@
+// run-pass
+// Test that the lifetime from the enclosing `&` is "inherited"
+// through the `MyBox` struct.
+
+// pretty-expanded FIXME #23616
+
+#![allow(dead_code)]
+
+trait Test {
+    fn foo(&self) { }
+}
+
+struct SomeStruct<'a> {
+    t: &'a MyBox<dyn Test>,
+    u: &'a MyBox<dyn Test+'a>,
+}
+
+struct MyBox<T:?Sized> {
+    b: Box<T>
+}
+
+fn a<'a>(t: &'a MyBox<dyn Test>, mut ss: SomeStruct<'a>) {
+    ss.t = t;
+}
+
+fn b<'a>(t: &'a MyBox<dyn Test>, mut ss: SomeStruct<'a>) {
+    ss.u = t;
+}
+
+// see also ui/object-lifetime/object-lifetime-default-from-rptr-box-error.rs
+
+fn d<'a>(t: &'a MyBox<dyn Test+'a>, mut ss: SomeStruct<'a>) {
+    ss.u = t;
+}
+
+fn main() {
+}
diff --git a/tests/ui/object-lifetime/object-lifetime-default-from-rptr.rs b/tests/ui/object-lifetime/object-lifetime-default-from-rptr.rs
new file mode 100644
index 00000000000..5093b1c27d0
--- /dev/null
+++ b/tests/ui/object-lifetime/object-lifetime-default-from-rptr.rs
@@ -0,0 +1,42 @@
+// run-pass
+// Test that the lifetime of the enclosing `&` is used for the object
+// lifetime bound.
+
+// pretty-expanded FIXME #23616
+
+#![allow(dead_code)]
+
+use std::fmt::Display;
+
+trait Test {
+    fn foo(&self) { }
+}
+
+struct SomeStruct<'a> {
+    t: &'a dyn Test,
+    u: &'a (dyn Test+'a),
+}
+
+fn a<'a>(t: &'a dyn Test, mut ss: SomeStruct<'a>) {
+    ss.t = t;
+}
+
+fn b<'a>(t: &'a dyn Test, mut ss: SomeStruct<'a>) {
+    ss.u = t;
+}
+
+fn c<'a>(t: &'a (dyn Test+'a), mut ss: SomeStruct<'a>) {
+    ss.t = t;
+}
+
+fn d<'a>(t: &'a (dyn Test+'a), mut ss: SomeStruct<'a>) {
+    ss.u = t;
+}
+
+fn e<'a>(_: &'a (dyn Display+'static)) {}
+
+fn main() {
+    // Inside a function body, we can just infer both
+    // lifetimes, to allow &'tmp (Display+'static).
+    e(&0 as &dyn Display);
+}
diff --git a/tests/ui/object-lifetime/object-lifetime-default-inferred.rs b/tests/ui/object-lifetime/object-lifetime-default-inferred.rs
new file mode 100644
index 00000000000..8a1156b8fc8
--- /dev/null
+++ b/tests/ui/object-lifetime/object-lifetime-default-inferred.rs
@@ -0,0 +1,35 @@
+// run-pass
+// Test that even with prior inferred parameters, object lifetimes of objects after are still
+// valid.
+
+// pretty-expanded FIXME #23616
+
+#![allow(dead_code)]
+#![feature(generic_arg_infer)]
+
+trait Test {
+    fn foo(&self) { }
+}
+
+struct Foo;
+impl Test for Foo {}
+
+struct SomeStruct<'a> {
+    t: &'a dyn Test,
+    u: &'a (dyn Test+'a),
+}
+
+fn a<'a, const N: usize>(_: [u8; N], t: &'a (dyn Test+'a), mut ss: SomeStruct<'a>) {
+    ss.t = t;
+}
+
+fn b<'a, T>(_: T, t: &'a (dyn Test+'a), mut ss: SomeStruct<'a>) {
+    ss.u = t;
+}
+
+fn main() {
+    // Inside a function body, we can just infer both
+    // lifetimes, to allow &'tmp (Display+'static).
+    a::<_>([], &Foo as &dyn Test, SomeStruct{t:&Foo,u:&Foo});
+    b::<_>(0u8, &Foo as &dyn Test, SomeStruct{t:&Foo,u:&Foo});
+}
diff --git a/tests/ui/object-lifetime/object-lifetime-default-mybox.rs b/tests/ui/object-lifetime/object-lifetime-default-mybox.rs
new file mode 100644
index 00000000000..5e6e5e2c063
--- /dev/null
+++ b/tests/ui/object-lifetime/object-lifetime-default-mybox.rs
@@ -0,0 +1,37 @@
+// Test a "pass-through" object-lifetime-default that produces errors.
+
+#![allow(dead_code)]
+
+trait SomeTrait {
+    fn dummy(&self) { }
+}
+
+struct MyBox<T:?Sized> {
+    r: Box<T>
+}
+
+fn deref<T>(ss: &T) -> T {
+    // produces the type of a deref without worrying about whether a
+    // move out would actually be legal
+    loop { }
+}
+
+fn load0(ss: &MyBox<dyn SomeTrait>) -> MyBox<dyn SomeTrait> {
+    deref(ss)
+}
+
+fn load1<'a,'b>(a: &'a MyBox<dyn SomeTrait>,
+                b: &'b MyBox<dyn SomeTrait>)
+                -> &'b MyBox<dyn SomeTrait>
+{
+    a
+    //~^ ERROR lifetime may not live long enough
+}
+
+fn load2<'a>(ss: &MyBox<dyn SomeTrait + 'a>) -> MyBox<dyn SomeTrait + 'a> {
+    load0(ss)
+    //~^ ERROR borrowed data escapes outside of function
+}
+
+fn main() {
+}
diff --git a/tests/ui/object-lifetime/object-lifetime-default-mybox.stderr b/tests/ui/object-lifetime/object-lifetime-default-mybox.stderr
new file mode 100644
index 00000000000..a1ef0243e3a
--- /dev/null
+++ b/tests/ui/object-lifetime/object-lifetime-default-mybox.stderr
@@ -0,0 +1,29 @@
+error: lifetime may not live long enough
+  --> $DIR/object-lifetime-default-mybox.rs:27:5
+   |
+LL | fn load1<'a,'b>(a: &'a MyBox<dyn SomeTrait>,
+   |          -- -- lifetime `'b` defined here
+   |          |
+   |          lifetime `'a` defined here
+...
+LL |     a
+   |     ^ function was supposed to return data with lifetime `'b` but it is returning data with lifetime `'a`
+   |
+   = help: consider adding the following bound: `'a: 'b`
+
+error[E0521]: borrowed data escapes outside of function
+  --> $DIR/object-lifetime-default-mybox.rs:32:5
+   |
+LL | fn load2<'a>(ss: &MyBox<dyn SomeTrait + 'a>) -> MyBox<dyn SomeTrait + 'a> {
+   |          --  -- `ss` is a reference that is only valid in the function body
+   |          |
+   |          lifetime `'a` defined here
+LL |     load0(ss)
+   |     ^^^^^^^^^
+   |     |
+   |     `ss` escapes the function body here
+   |     argument requires that `'a` must outlive `'static`
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0521`.
diff --git a/tests/ui/object-lifetime/object-lifetime-default.rs b/tests/ui/object-lifetime/object-lifetime-default.rs
new file mode 100644
index 00000000000..74f5bb7ddb0
--- /dev/null
+++ b/tests/ui/object-lifetime/object-lifetime-default.rs
@@ -0,0 +1,50 @@
+#![feature(rustc_attrs)]
+
+#[rustc_object_lifetime_default]
+struct A<
+    T, //~ ERROR BaseDefault
+>(T);
+
+#[rustc_object_lifetime_default]
+struct B<
+    'a,
+    T, //~ ERROR BaseDefault
+>(&'a (), T);
+
+#[rustc_object_lifetime_default]
+struct C<
+    'a,
+    T: 'a, //~ ERROR 'a
+>(&'a T);
+
+#[rustc_object_lifetime_default]
+struct D<
+    'a,
+    'b,
+    T: 'a + 'b, //~ ERROR Ambiguous
+>(&'a T, &'b T);
+
+#[rustc_object_lifetime_default]
+struct E<
+    'a,
+    'b: 'a,
+    T: 'b, //~ ERROR 'b
+>(&'a T, &'b T);
+
+#[rustc_object_lifetime_default]
+struct F<
+    'a,
+    'b,
+    T: 'a, //~ ERROR 'a
+    U: 'b, //~ ERROR 'b
+>(&'a T, &'b U);
+
+#[rustc_object_lifetime_default]
+struct G<
+    'a,
+    'b,
+    T: 'a,      //~ ERROR 'a
+    U: 'a + 'b, //~ ERROR Ambiguous
+>(&'a T, &'b U);
+
+fn main() {}
diff --git a/tests/ui/object-lifetime/object-lifetime-default.stderr b/tests/ui/object-lifetime/object-lifetime-default.stderr
new file mode 100644
index 00000000000..a58afad3ef2
--- /dev/null
+++ b/tests/ui/object-lifetime/object-lifetime-default.stderr
@@ -0,0 +1,56 @@
+error: BaseDefault
+  --> $DIR/object-lifetime-default.rs:5:5
+   |
+LL |     T,
+   |     ^
+
+error: BaseDefault
+  --> $DIR/object-lifetime-default.rs:11:5
+   |
+LL |     T,
+   |     ^
+
+error: 'a
+  --> $DIR/object-lifetime-default.rs:17:5
+   |
+LL |     T: 'a,
+   |     ^
+
+error: Ambiguous
+  --> $DIR/object-lifetime-default.rs:24:5
+   |
+LL |     T: 'a + 'b,
+   |     ^
+
+error: 'b
+  --> $DIR/object-lifetime-default.rs:31:5
+   |
+LL |     T: 'b,
+   |     ^
+
+error: 'a
+  --> $DIR/object-lifetime-default.rs:38:5
+   |
+LL |     T: 'a,
+   |     ^
+
+error: 'b
+  --> $DIR/object-lifetime-default.rs:39:5
+   |
+LL |     U: 'b,
+   |     ^
+
+error: 'a
+  --> $DIR/object-lifetime-default.rs:46:5
+   |
+LL |     T: 'a,
+   |     ^
+
+error: Ambiguous
+  --> $DIR/object-lifetime-default.rs:47:5
+   |
+LL |     U: 'a + 'b,
+   |     ^
+
+error: aborting due to 9 previous errors
+