summaryrefslogtreecommitdiffstats
path: root/src/test/ui/dropck
diff options
context:
space:
mode:
Diffstat (limited to 'src/test/ui/dropck')
-rw-r--r--src/test/ui/dropck/auxiliary/dropck_eyepatch_extern_crate.rs37
-rw-r--r--src/test/ui/dropck/cleanup-arm-conditional.rs39
-rw-r--r--src/test/ui/dropck/drop-on-non-struct.rs15
-rw-r--r--src/test/ui/dropck/drop-on-non-struct.stderr27
-rw-r--r--src/test/ui/dropck/drop-with-active-borrows-1.rs8
-rw-r--r--src/test/ui/dropck/drop-with-active-borrows-1.stderr13
-rw-r--r--src/test/ui/dropck/drop-with-active-borrows-2.rs9
-rw-r--r--src/test/ui/dropck/drop-with-active-borrows-2.stderr12
-rw-r--r--src/test/ui/dropck/dropck-eyepatch-extern-crate.rs82
-rw-r--r--src/test/ui/dropck/dropck-eyepatch-extern-crate.stderr31
-rw-r--r--src/test/ui/dropck/dropck-eyepatch-implies-unsafe-impl.rs35
-rw-r--r--src/test/ui/dropck/dropck-eyepatch-implies-unsafe-impl.stderr25
-rw-r--r--src/test/ui/dropck/dropck-eyepatch-reorder.rs100
-rw-r--r--src/test/ui/dropck/dropck-eyepatch-reorder.stderr31
-rw-r--r--src/test/ui/dropck/dropck-eyepatch.rs123
-rw-r--r--src/test/ui/dropck/dropck-eyepatch.stderr31
-rw-r--r--src/test/ui/dropck/dropck-union.rs38
-rw-r--r--src/test/ui/dropck/dropck-union.stderr14
-rw-r--r--src/test/ui/dropck/dropck_fn_type.rs20
-rw-r--r--src/test/ui/dropck/dropck_no_diverge_on_nonregular_1.rs26
-rw-r--r--src/test/ui/dropck/dropck_no_diverge_on_nonregular_1.stderr10
-rw-r--r--src/test/ui/dropck/dropck_no_diverge_on_nonregular_2.rs25
-rw-r--r--src/test/ui/dropck/dropck_no_diverge_on_nonregular_2.stderr10
-rw-r--r--src/test/ui/dropck/dropck_no_diverge_on_nonregular_3.rs35
-rw-r--r--src/test/ui/dropck/dropck_no_diverge_on_nonregular_3.stderr18
-rw-r--r--src/test/ui/dropck/dropck_trait_cycle_checked.rs121
-rw-r--r--src/test/ui/dropck/dropck_trait_cycle_checked.stderr73
-rw-r--r--src/test/ui/dropck/dropck_traits.rs68
-rw-r--r--src/test/ui/dropck/issue-28498-ugeh-with-lifetime-param.rs38
-rw-r--r--src/test/ui/dropck/issue-28498-ugeh-with-passed-to-fn.rs46
-rw-r--r--src/test/ui/dropck/issue-28498-ugeh-with-trait-bound.rs41
-rw-r--r--src/test/ui/dropck/issue-29844.rs24
-rw-r--r--src/test/ui/dropck/issue-38868.rs13
-rw-r--r--src/test/ui/dropck/issue-38868.stderr16
-rw-r--r--src/test/ui/dropck/reject-specialized-drops-8142.rs75
-rw-r--r--src/test/ui/dropck/reject-specialized-drops-8142.stderr166
-rw-r--r--src/test/ui/dropck/relate_lt_in_type_outlives_bound.rs13
-rw-r--r--src/test/ui/dropck/relate_lt_in_type_outlives_bound.stderr15
38 files changed, 1523 insertions, 0 deletions
diff --git a/src/test/ui/dropck/auxiliary/dropck_eyepatch_extern_crate.rs b/src/test/ui/dropck/auxiliary/dropck_eyepatch_extern_crate.rs
new file mode 100644
index 000000000..e07082957
--- /dev/null
+++ b/src/test/ui/dropck/auxiliary/dropck_eyepatch_extern_crate.rs
@@ -0,0 +1,37 @@
+#![feature(dropck_eyepatch)]
+
+// This is a support file for ../dropck-eyepatch-extern-crate.rs
+//
+// The point of this test is to illustrate that the `#[may_dangle]`
+// attribute specifically allows, in the context of a type
+// implementing `Drop`, a generic parameter to be instantiated with a
+// lifetime that does not strictly outlive the owning type itself,
+// and that this attribute's effects are preserved when importing
+// the type from another crate.
+//
+// See also ../dropck-eyepatch.rs for more information about the general
+// structure of the test.
+
+use std::fmt;
+
+pub struct Dt<A: fmt::Debug>(pub &'static str, pub A);
+pub struct Dr<'a, B:'a+fmt::Debug>(pub &'static str, pub &'a B);
+pub struct Pt<A,B: fmt::Debug>(pub &'static str, pub A, pub B);
+pub struct Pr<'a, 'b, B:'a+'b+fmt::Debug>(pub &'static str, pub &'a B, pub &'b B);
+pub struct St<A: fmt::Debug>(pub &'static str, pub A);
+pub struct Sr<'a, B:'a+fmt::Debug>(pub &'static str, pub &'a B);
+
+impl<A: fmt::Debug> Drop for Dt<A> {
+ fn drop(&mut self) { println!("drop {} {:?}", self.0, self.1); }
+}
+impl<'a, B: fmt::Debug> Drop for Dr<'a, B> {
+ fn drop(&mut self) { println!("drop {} {:?}", self.0, self.1); }
+}
+unsafe impl<#[may_dangle] A, B: fmt::Debug> Drop for Pt<A, B> {
+ // (unsafe to access self.1 due to #[may_dangle] on A)
+ fn drop(&mut self) { println!("drop {} {:?}", self.0, self.2); }
+}
+unsafe impl<#[may_dangle] 'a, 'b, B: fmt::Debug> Drop for Pr<'a, 'b, B> {
+ // (unsafe to access self.1 due to #[may_dangle] on 'a)
+ fn drop(&mut self) { println!("drop {} {:?}", self.0, self.2); }
+}
diff --git a/src/test/ui/dropck/cleanup-arm-conditional.rs b/src/test/ui/dropck/cleanup-arm-conditional.rs
new file mode 100644
index 000000000..38c717089
--- /dev/null
+++ b/src/test/ui/dropck/cleanup-arm-conditional.rs
@@ -0,0 +1,39 @@
+// run-pass
+
+#![allow(stable_features)]
+#![allow(unused_imports)]
+// Test that cleanup scope for temporaries created in a match
+// arm is confined to the match arm itself.
+
+// pretty-expanded FIXME #23616
+
+#![feature(os)]
+
+use std::os;
+
+struct Test { x: isize }
+
+impl Test {
+ fn get_x(&self) -> Option<Box<isize>> {
+ Some(Box::new(self.x))
+ }
+}
+
+fn do_something(t: &Test) -> isize {
+
+ // The cleanup scope for the result of `t.get_x()` should be the
+ // arm itself and not the match, otherwise we'll (potentially) get
+ // a crash trying to free an uninitialized stack slot.
+
+ match t {
+ &Test { x: 2 } if t.get_x().is_some() => {
+ t.x * 2
+ }
+ _ => { 22 }
+ }
+}
+
+pub fn main() {
+ let t = Test { x: 1 };
+ do_something(&t);
+}
diff --git a/src/test/ui/dropck/drop-on-non-struct.rs b/src/test/ui/dropck/drop-on-non-struct.rs
new file mode 100644
index 000000000..ef5e18126
--- /dev/null
+++ b/src/test/ui/dropck/drop-on-non-struct.rs
@@ -0,0 +1,15 @@
+impl<'a> Drop for &'a mut isize {
+ //~^ ERROR the `Drop` trait may only be implemented for structs, enums, and unions
+ //~^^ ERROR E0117
+ fn drop(&mut self) {
+ println!("kaboom");
+ }
+}
+
+impl Drop for Nonexistent {
+ //~^ ERROR cannot find type `Nonexistent`
+ fn drop(&mut self) { }
+}
+
+fn main() {
+}
diff --git a/src/test/ui/dropck/drop-on-non-struct.stderr b/src/test/ui/dropck/drop-on-non-struct.stderr
new file mode 100644
index 000000000..e52728f37
--- /dev/null
+++ b/src/test/ui/dropck/drop-on-non-struct.stderr
@@ -0,0 +1,27 @@
+error[E0412]: cannot find type `Nonexistent` in this scope
+ --> $DIR/drop-on-non-struct.rs:9:15
+ |
+LL | impl Drop for Nonexistent {
+ | ^^^^^^^^^^^ not found in this scope
+
+error[E0117]: only traits defined in the current crate can be implemented for arbitrary types
+ --> $DIR/drop-on-non-struct.rs:1:1
+ |
+LL | impl<'a> Drop for &'a mut isize {
+ | ^^^^^^^^^^^^^^^^^^-------------
+ | | |
+ | | `isize` is not defined in the current crate
+ | impl doesn't use only types from inside the current crate
+ |
+ = note: define and implement a trait or new type instead
+
+error[E0120]: the `Drop` trait may only be implemented for structs, enums, and unions
+ --> $DIR/drop-on-non-struct.rs:1:19
+ |
+LL | impl<'a> Drop for &'a mut isize {
+ | ^^^^^^^^^^^^^ must be a struct, enum, or union
+
+error: aborting due to 3 previous errors
+
+Some errors have detailed explanations: E0117, E0120, E0412.
+For more information about an error, try `rustc --explain E0117`.
diff --git a/src/test/ui/dropck/drop-with-active-borrows-1.rs b/src/test/ui/dropck/drop-with-active-borrows-1.rs
new file mode 100644
index 000000000..1e924af29
--- /dev/null
+++ b/src/test/ui/dropck/drop-with-active-borrows-1.rs
@@ -0,0 +1,8 @@
+fn main() {
+ let a = "".to_string();
+ let b: Vec<&str> = a.lines().collect();
+ drop(a); //~ ERROR cannot move out of `a` because it is borrowed
+ for s in &b {
+ println!("{}", *s);
+ }
+}
diff --git a/src/test/ui/dropck/drop-with-active-borrows-1.stderr b/src/test/ui/dropck/drop-with-active-borrows-1.stderr
new file mode 100644
index 000000000..8d6a7f372
--- /dev/null
+++ b/src/test/ui/dropck/drop-with-active-borrows-1.stderr
@@ -0,0 +1,13 @@
+error[E0505]: cannot move out of `a` because it is borrowed
+ --> $DIR/drop-with-active-borrows-1.rs:4:10
+ |
+LL | let b: Vec<&str> = a.lines().collect();
+ | --------- borrow of `a` occurs here
+LL | drop(a);
+ | ^ move out of `a` occurs here
+LL | for s in &b {
+ | -- borrow later used here
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0505`.
diff --git a/src/test/ui/dropck/drop-with-active-borrows-2.rs b/src/test/ui/dropck/drop-with-active-borrows-2.rs
new file mode 100644
index 000000000..cf4cb3dbe
--- /dev/null
+++ b/src/test/ui/dropck/drop-with-active-borrows-2.rs
@@ -0,0 +1,9 @@
+fn read_lines_borrowed<'a>() -> Vec<&'a str> {
+ let raw_lines: Vec<String> = vec!["foo ".to_string(), " bar".to_string()];
+ raw_lines.iter().map(|l| l.trim()).collect()
+ //~^ ERROR cannot return value referencing local variable `raw_lines`
+}
+
+fn main() {
+ println!("{:?}", read_lines_borrowed());
+}
diff --git a/src/test/ui/dropck/drop-with-active-borrows-2.stderr b/src/test/ui/dropck/drop-with-active-borrows-2.stderr
new file mode 100644
index 000000000..24650dfac
--- /dev/null
+++ b/src/test/ui/dropck/drop-with-active-borrows-2.stderr
@@ -0,0 +1,12 @@
+error[E0515]: cannot return value referencing local variable `raw_lines`
+ --> $DIR/drop-with-active-borrows-2.rs:3:5
+ |
+LL | raw_lines.iter().map(|l| l.trim()).collect()
+ | ----------------^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ | |
+ | returns a value referencing data owned by the current function
+ | `raw_lines` is borrowed here
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0515`.
diff --git a/src/test/ui/dropck/dropck-eyepatch-extern-crate.rs b/src/test/ui/dropck/dropck-eyepatch-extern-crate.rs
new file mode 100644
index 000000000..b8f303554
--- /dev/null
+++ b/src/test/ui/dropck/dropck-eyepatch-extern-crate.rs
@@ -0,0 +1,82 @@
+// aux-build:dropck_eyepatch_extern_crate.rs
+
+// The point of this test is to illustrate that the `#[may_dangle]`
+// attribute specifically allows, in the context of a type
+// implementing `Drop`, a generic parameter to be instantiated with a
+// lifetime that does not strictly outlive the owning type itself,
+// and that this attribute's effects are preserved when importing
+// the type from another crate.
+//
+// See also dropck-eyepatch.rs for more information about the general
+// structure of the test.
+extern crate dropck_eyepatch_extern_crate as other;
+
+use other::{Dt,Dr,Pt,Pr,St,Sr};
+
+fn main() {
+ use std::cell::Cell;
+
+ // We use separate blocks with separate variable to prevent the error
+ // messages from being deduplicated.
+
+ {
+ let c_long;
+ let (mut dt, mut dr): (Dt<_>, Dr<_>);
+ c_long = Cell::new(1);
+
+ // No error: sufficiently long-lived state can be referenced in dtors
+ dt = Dt("dt", &c_long);
+ dr = Dr("dr", &c_long);
+ }
+
+ {
+ let (c, mut dt, mut dr): (Cell<_>, Dt<_>, Dr<_>);
+ c = Cell::new(1);
+
+ // No Error: destructor order precisely modelled
+ dt = Dt("dt", &c);
+ dr = Dr("dr", &c);
+ }
+
+ {
+ let (mut dt, mut dr, c_shortest): (Dt<_>, Dr<_>, Cell<_>);
+ c_shortest = Cell::new(1);
+
+ // Error: `c_shortest` dies too soon for the references in dtors to be valid.
+ dt = Dt("dt", &c_shortest);
+ //~^ ERROR `c_shortest` does not live long enough
+ dr = Dr("dr", &c_shortest);
+ }
+
+ {
+ let c_long;
+ let (mut pt, mut pr, c_shortest): (Pt<_, _>, Pr<_>, Cell<_>);
+ c_long = Cell::new(1);
+ c_shortest = Cell::new(1);
+
+ // No error: Drop impl asserts .1 (A and &'a _) are not accessed
+ pt = Pt("pt", &c_shortest, &c_long);
+ pr = Pr("pr", &c_shortest, &c_long);
+ }
+
+ {
+ let c_long;
+ let (mut pt, mut pr, c_shortest): (Pt<_, _>, Pr<_>, Cell<_>);
+ c_long = Cell::new(1);
+ c_shortest = Cell::new(1);
+ // Error: Drop impl's assertion does not apply to `B` nor `&'b _`
+ pt = Pt("pt", &c_long, &c_shortest);
+ //~^ ERROR `c_shortest` does not live long enough
+ pr = Pr("pr", &c_long, &c_shortest);
+ }
+
+ {
+ let (st, sr, c_shortest): (St<_>, Sr<_>, Cell<_>);
+ c_shortest = Cell::new(1);
+ // No error: St and Sr have no destructor.
+ st = St("st", &c_shortest);
+ sr = Sr("sr", &c_shortest);
+ }
+}
+
+fn use_imm<T>(_: &T) { }
diff --git a/src/test/ui/dropck/dropck-eyepatch-extern-crate.stderr b/src/test/ui/dropck/dropck-eyepatch-extern-crate.stderr
new file mode 100644
index 000000000..5d5340557
--- /dev/null
+++ b/src/test/ui/dropck/dropck-eyepatch-extern-crate.stderr
@@ -0,0 +1,31 @@
+error[E0597]: `c_shortest` does not live long enough
+ --> $DIR/dropck-eyepatch-extern-crate.rs:46:23
+ |
+LL | dt = Dt("dt", &c_shortest);
+ | ^^^^^^^^^^^ borrowed value does not live long enough
+...
+LL | }
+ | -
+ | |
+ | `c_shortest` dropped here while still borrowed
+ | borrow might be used here, when `dt` is dropped and runs the `Drop` code for type `Dt`
+ |
+ = note: values in a scope are dropped in the opposite order they are defined
+
+error[E0597]: `c_shortest` does not live long enough
+ --> $DIR/dropck-eyepatch-extern-crate.rs:68:32
+ |
+LL | pt = Pt("pt", &c_long, &c_shortest);
+ | ^^^^^^^^^^^ borrowed value does not live long enough
+...
+LL | }
+ | -
+ | |
+ | `c_shortest` dropped here while still borrowed
+ | borrow might be used here, when `pt` is dropped and runs the `Drop` code for type `Pt`
+ |
+ = note: values in a scope are dropped in the opposite order they are defined
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0597`.
diff --git a/src/test/ui/dropck/dropck-eyepatch-implies-unsafe-impl.rs b/src/test/ui/dropck/dropck-eyepatch-implies-unsafe-impl.rs
new file mode 100644
index 000000000..6869ab1c4
--- /dev/null
+++ b/src/test/ui/dropck/dropck-eyepatch-implies-unsafe-impl.rs
@@ -0,0 +1,35 @@
+#![feature(dropck_eyepatch)]
+
+// This test ensures that a use of `#[may_dangle]` is rejected if
+// it is not attached to an `unsafe impl`.
+
+use std::fmt;
+
+struct Dt<A: fmt::Debug>(&'static str, A);
+struct Dr<'a, B:'a+fmt::Debug>(&'static str, &'a B);
+struct Pt<A,B: fmt::Debug>(&'static str, A, B);
+struct Pr<'a, 'b, B:'a+'b+fmt::Debug>(&'static str, &'a B, &'b B);
+struct St<A: fmt::Debug>(&'static str, A);
+struct Sr<'a, B:'a+fmt::Debug>(&'static str, &'a B);
+
+impl<A: fmt::Debug> Drop for Dt<A> {
+ fn drop(&mut self) { println!("drop {} {:?}", self.0, self.1); }
+}
+impl<'a, B: fmt::Debug> Drop for Dr<'a, B> {
+ fn drop(&mut self) { println!("drop {} {:?}", self.0, self.1); }
+}
+impl<#[may_dangle] A, B: fmt::Debug> Drop for Pt<A, B> {
+ //~^ ERROR requires an `unsafe impl` declaration due to `#[may_dangle]` attribute
+
+ // (unsafe to access self.1 due to #[may_dangle] on A)
+ fn drop(&mut self) { println!("drop {} {:?}", self.0, self.2); }
+}
+impl<#[may_dangle] 'a, 'b, B: fmt::Debug> Drop for Pr<'a, 'b, B> {
+ //~^ ERROR requires an `unsafe impl` declaration due to `#[may_dangle]` attribute
+
+ // (unsafe to access self.1 due to #[may_dangle] on 'a)
+ fn drop(&mut self) { println!("drop {} {:?}", self.0, self.2); }
+}
+
+fn main() {
+}
diff --git a/src/test/ui/dropck/dropck-eyepatch-implies-unsafe-impl.stderr b/src/test/ui/dropck/dropck-eyepatch-implies-unsafe-impl.stderr
new file mode 100644
index 000000000..49e55be1b
--- /dev/null
+++ b/src/test/ui/dropck/dropck-eyepatch-implies-unsafe-impl.stderr
@@ -0,0 +1,25 @@
+error[E0569]: requires an `unsafe impl` declaration due to `#[may_dangle]` attribute
+ --> $DIR/dropck-eyepatch-implies-unsafe-impl.rs:21:1
+ |
+LL | / impl<#[may_dangle] A, B: fmt::Debug> Drop for Pt<A, B> {
+LL | |
+LL | |
+LL | | // (unsafe to access self.1 due to #[may_dangle] on A)
+LL | | fn drop(&mut self) { println!("drop {} {:?}", self.0, self.2); }
+LL | | }
+ | |_^
+
+error[E0569]: requires an `unsafe impl` declaration due to `#[may_dangle]` attribute
+ --> $DIR/dropck-eyepatch-implies-unsafe-impl.rs:27:1
+ |
+LL | / impl<#[may_dangle] 'a, 'b, B: fmt::Debug> Drop for Pr<'a, 'b, B> {
+LL | |
+LL | |
+LL | | // (unsafe to access self.1 due to #[may_dangle] on 'a)
+LL | | fn drop(&mut self) { println!("drop {} {:?}", self.0, self.2); }
+LL | | }
+ | |_^
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0569`.
diff --git a/src/test/ui/dropck/dropck-eyepatch-reorder.rs b/src/test/ui/dropck/dropck-eyepatch-reorder.rs
new file mode 100644
index 000000000..44552b3fc
--- /dev/null
+++ b/src/test/ui/dropck/dropck-eyepatch-reorder.rs
@@ -0,0 +1,100 @@
+#![feature(dropck_eyepatch)]
+
+// The point of this test is to test uses of `#[may_dangle]` attribute
+// where the formal declaration order (in the impl generics) does not
+// match the actual usage order (in the type instantiation).
+//
+// See also dropck-eyepatch.rs for more information about the general
+// structure of the test.
+
+use std::fmt;
+
+struct Dt<A: fmt::Debug>(&'static str, A);
+struct Dr<'a, B:'a+fmt::Debug>(&'static str, &'a B);
+struct Pt<A: fmt::Debug, B: fmt::Debug>(&'static str, A, B);
+struct Pr<'a, 'b, B:'a+'b+fmt::Debug>(&'static str, &'a B, &'b B);
+struct St<A: fmt::Debug>(&'static str, A);
+struct Sr<'a, B:'a+fmt::Debug>(&'static str, &'a B);
+
+impl<A: fmt::Debug> Drop for Dt<A> {
+ fn drop(&mut self) { println!("drop {} {:?}", self.0, self.1); }
+}
+impl<'a, B: fmt::Debug> Drop for Dr<'a, B> {
+ fn drop(&mut self) { println!("drop {} {:?}", self.0, self.1); }
+}
+unsafe impl<B: fmt::Debug, #[may_dangle] A: fmt::Debug> Drop for Pt<A, B> {
+ // (unsafe to access self.1 due to #[may_dangle] on A)
+ fn drop(&mut self) { println!("drop {} {:?}", self.0, self.2); }
+}
+unsafe impl<'b, #[may_dangle] 'a, B: fmt::Debug> Drop for Pr<'a, 'b, B> {
+ // (unsafe to access self.1 due to #[may_dangle] on 'a)
+ fn drop(&mut self) { println!("drop {} {:?}", self.0, self.2); }
+}
+
+fn main() {
+ use std::cell::Cell;
+
+ // We use separate blocks with separate variable to prevent the error
+ // messages from being deduplicated.
+
+ {
+ let c_long;
+ let (mut dt, mut dr): (Dt<_>, Dr<_>);
+ c_long = Cell::new(1);
+
+ // No error: sufficiently long-lived state can be referenced in dtors
+ dt = Dt("dt", &c_long);
+ dr = Dr("dr", &c_long);
+ }
+
+ {
+ let (c, mut dt, mut dr): (Cell<_>, Dt<_>, Dr<_>);
+ c = Cell::new(1);
+
+ // No Error: destructor order precisely modelled
+ dt = Dt("dt", &c);
+ dr = Dr("dr", &c);
+ }
+
+ {
+ let (mut dt, mut dr, c_shortest): (Dt<_>, Dr<_>, Cell<_>);
+ c_shortest = Cell::new(1);
+
+ // Error: `c_shortest` dies too soon for the references in dtors to be valid.
+ dt = Dt("dt", &c_shortest);
+ //~^ ERROR `c_shortest` does not live long enough
+ dr = Dr("dr", &c_shortest);
+ }
+
+ {
+ let c_long;
+ let (mut pt, mut pr, c_shortest): (Pt<_, _>, Pr<_>, Cell<_>);
+ c_long = Cell::new(1);
+ c_shortest = Cell::new(1);
+
+ // No error: Drop impl asserts .1 (A and &'a _) are not accessed
+ pt = Pt("pt", &c_shortest, &c_long);
+ pr = Pr("pr", &c_shortest, &c_long);
+ }
+
+ {
+ let c_long;
+ let (mut pt, mut pr, c_shortest): (Pt<_, _>, Pr<_>, Cell<_>);
+ c_long = Cell::new(1);
+ c_shortest = Cell::new(1);
+ // Error: Drop impl's assertion does not apply to `B` nor `&'b _`
+ pt = Pt("pt", &c_long, &c_shortest);
+ //~^ ERROR `c_shortest` does not live long enough
+ pr = Pr("pr", &c_long, &c_shortest);
+ }
+
+ {
+ let (st, sr, c_shortest): (St<_>, Sr<_>, Cell<_>);
+ c_shortest = Cell::new(1);
+ // No error: St and Sr have no destructor.
+ st = St("st", &c_shortest);
+ sr = Sr("sr", &c_shortest);
+ }
+}
+
+fn use_imm<T>(_: &T) { }
diff --git a/src/test/ui/dropck/dropck-eyepatch-reorder.stderr b/src/test/ui/dropck/dropck-eyepatch-reorder.stderr
new file mode 100644
index 000000000..5055cdd8b
--- /dev/null
+++ b/src/test/ui/dropck/dropck-eyepatch-reorder.stderr
@@ -0,0 +1,31 @@
+error[E0597]: `c_shortest` does not live long enough
+ --> $DIR/dropck-eyepatch-reorder.rs:64:23
+ |
+LL | dt = Dt("dt", &c_shortest);
+ | ^^^^^^^^^^^ borrowed value does not live long enough
+...
+LL | }
+ | -
+ | |
+ | `c_shortest` dropped here while still borrowed
+ | borrow might be used here, when `dt` is dropped and runs the `Drop` code for type `Dt`
+ |
+ = note: values in a scope are dropped in the opposite order they are defined
+
+error[E0597]: `c_shortest` does not live long enough
+ --> $DIR/dropck-eyepatch-reorder.rs:86:32
+ |
+LL | pt = Pt("pt", &c_long, &c_shortest);
+ | ^^^^^^^^^^^ borrowed value does not live long enough
+...
+LL | }
+ | -
+ | |
+ | `c_shortest` dropped here while still borrowed
+ | borrow might be used here, when `pt` is dropped and runs the `Drop` code for type `Pt`
+ |
+ = note: values in a scope are dropped in the opposite order they are defined
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0597`.
diff --git a/src/test/ui/dropck/dropck-eyepatch.rs b/src/test/ui/dropck/dropck-eyepatch.rs
new file mode 100644
index 000000000..ec1c68561
--- /dev/null
+++ b/src/test/ui/dropck/dropck-eyepatch.rs
@@ -0,0 +1,123 @@
+#![feature(dropck_eyepatch)]
+
+// The point of this test is to illustrate that the `#[may_dangle]`
+// attribute specifically allows, in the context of a type
+// implementing `Drop`, a generic parameter to be instantiated with a
+// lifetime that does not strictly outlive the owning type itself.
+//
+// Here we test that only the expected errors are issued.
+//
+// The illustration is made concrete by comparison with two variations
+// on the type with `#[may_dangle]`:
+//
+// 1. an analogous type that does not implement `Drop` (and thus
+// should exhibit maximal flexibility with respect to dropck), and
+//
+// 2. an analogous type that does not use `#[may_dangle]` (and thus
+// should exhibit the standard limitations imposed by dropck.
+//
+// The types in this file follow a pattern, {D,P,S}{t,r}, where:
+//
+// - D means "I implement Drop"
+//
+// - P means "I implement Drop but guarantee my (first) parameter is
+// pure, i.e., not accessed from the destructor"; no other parameters
+// are pure.
+//
+// - S means "I do not implement Drop"
+//
+// - t suffix is used when the first generic is a type
+//
+// - r suffix is used when the first generic is a lifetime.
+
+use std::fmt;
+
+struct Dt<A: fmt::Debug>(&'static str, A);
+struct Dr<'a, B:'a+fmt::Debug>(&'static str, &'a B);
+struct Pt<A,B: fmt::Debug>(&'static str, A, B);
+struct Pr<'a, 'b, B:'a+'b+fmt::Debug>(&'static str, &'a B, &'b B);
+struct St<A: fmt::Debug>(&'static str, A);
+struct Sr<'a, B:'a+fmt::Debug>(&'static str, &'a B);
+
+impl<A: fmt::Debug> Drop for Dt<A> {
+ fn drop(&mut self) { println!("drop {} {:?}", self.0, self.1); }
+}
+impl<'a, B: fmt::Debug> Drop for Dr<'a, B> {
+ fn drop(&mut self) { println!("drop {} {:?}", self.0, self.1); }
+}
+unsafe impl<#[may_dangle] A, B: fmt::Debug> Drop for Pt<A, B> {
+ // (unsafe to access self.1 due to #[may_dangle] on A)
+ fn drop(&mut self) { println!("drop {} {:?}", self.0, self.2); }
+}
+unsafe impl<#[may_dangle] 'a, 'b, B: fmt::Debug> Drop for Pr<'a, 'b, B> {
+ // (unsafe to access self.1 due to #[may_dangle] on 'a)
+ fn drop(&mut self) { println!("drop {} {:?}", self.0, self.2); }
+}
+
+
+fn main() {
+ use std::cell::Cell;
+
+ // We use separate blocks with separate variable to prevent the error
+ // messages from being deduplicated.
+
+ {
+ let c_long;
+ let (mut dt, mut dr): (Dt<_>, Dr<_>);
+ c_long = Cell::new(1);
+
+ // No error: sufficiently long-lived state can be referenced in dtors
+ dt = Dt("dt", &c_long);
+ dr = Dr("dr", &c_long);
+ }
+
+ {
+ let (c, mut dt, mut dr): (Cell<_>, Dt<_>, Dr<_>);
+ c = Cell::new(1);
+
+ // No Error: destructor order precisely modelled
+ dt = Dt("dt", &c);
+ dr = Dr("dr", &c);
+ }
+
+ {
+ let (mut dt, mut dr, c_shortest): (Dt<_>, Dr<_>, Cell<_>);
+ c_shortest = Cell::new(1);
+
+ // Error: `c_shortest` dies too soon for the references in dtors to be valid.
+ dt = Dt("dt", &c_shortest);
+ //~^ ERROR `c_shortest` does not live long enough
+ dr = Dr("dr", &c_shortest);
+ }
+
+ {
+ let c_long;
+ let (mut pt, mut pr, c_shortest): (Pt<_, _>, Pr<_>, Cell<_>);
+ c_long = Cell::new(1);
+ c_shortest = Cell::new(1);
+
+ // No error: Drop impl asserts .1 (A and &'a _) are not accessed
+ pt = Pt("pt", &c_shortest, &c_long);
+ pr = Pr("pr", &c_shortest, &c_long);
+ }
+
+ {
+ let c_long;
+ let (mut pt, mut pr, c_shortest): (Pt<_, _>, Pr<_>, Cell<_>);
+ c_long = Cell::new(1);
+ c_shortest = Cell::new(1);
+ // Error: Drop impl's assertion does not apply to `B` nor `&'b _`
+ pt = Pt("pt", &c_long, &c_shortest);
+ //~^ ERROR `c_shortest` does not live long enough
+ pr = Pr("pr", &c_long, &c_shortest);
+ }
+
+ {
+ let (st, sr, c_shortest): (St<_>, Sr<_>, Cell<_>);
+ c_shortest = Cell::new(1);
+ // No error: St and Sr have no destructor.
+ st = St("st", &c_shortest);
+ sr = Sr("sr", &c_shortest);
+ }
+}
+fn use_imm<T>(_: &T) { }
diff --git a/src/test/ui/dropck/dropck-eyepatch.stderr b/src/test/ui/dropck/dropck-eyepatch.stderr
new file mode 100644
index 000000000..21295e6c6
--- /dev/null
+++ b/src/test/ui/dropck/dropck-eyepatch.stderr
@@ -0,0 +1,31 @@
+error[E0597]: `c_shortest` does not live long enough
+ --> $DIR/dropck-eyepatch.rs:88:23
+ |
+LL | dt = Dt("dt", &c_shortest);
+ | ^^^^^^^^^^^ borrowed value does not live long enough
+...
+LL | }
+ | -
+ | |
+ | `c_shortest` dropped here while still borrowed
+ | borrow might be used here, when `dt` is dropped and runs the `Drop` code for type `Dt`
+ |
+ = note: values in a scope are dropped in the opposite order they are defined
+
+error[E0597]: `c_shortest` does not live long enough
+ --> $DIR/dropck-eyepatch.rs:110:32
+ |
+LL | pt = Pt("pt", &c_long, &c_shortest);
+ | ^^^^^^^^^^^ borrowed value does not live long enough
+...
+LL | }
+ | -
+ | |
+ | `c_shortest` dropped here while still borrowed
+ | borrow might be used here, when `pt` is dropped and runs the `Drop` code for type `Pt`
+ |
+ = note: values in a scope are dropped in the opposite order they are defined
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0597`.
diff --git a/src/test/ui/dropck/dropck-union.rs b/src/test/ui/dropck/dropck-union.rs
new file mode 100644
index 000000000..5a9965db5
--- /dev/null
+++ b/src/test/ui/dropck/dropck-union.rs
@@ -0,0 +1,38 @@
+use std::cell::Cell;
+use std::ops::Deref;
+use std::mem::ManuallyDrop;
+
+union Wrap<T> { x: ManuallyDrop<T> }
+
+impl<T> Drop for Wrap<T> {
+ fn drop(&mut self) {
+ unsafe { std::ptr::drop_in_place(&mut *self.x as *mut T); }
+ }
+}
+
+impl<T> Wrap<T> {
+ fn new(x: T) -> Self {
+ Wrap { x: ManuallyDrop::new(x) }
+ }
+}
+
+impl<T> Deref for Wrap<T> {
+ type Target = T;
+ #[inline]
+ fn deref(&self) -> &Self::Target {
+ unsafe {
+ &self.x
+ }
+ }
+}
+
+struct C<'a>(Cell<Option<&'a C<'a>>>);
+
+impl<'a> Drop for C<'a> {
+ fn drop(&mut self) {}
+}
+
+fn main() {
+ let v : Wrap<C> = Wrap::new(C(Cell::new(None)));
+ v.0.set(Some(&v)); //~ ERROR: `v` does not live long enough
+}
diff --git a/src/test/ui/dropck/dropck-union.stderr b/src/test/ui/dropck/dropck-union.stderr
new file mode 100644
index 000000000..854e29385
--- /dev/null
+++ b/src/test/ui/dropck/dropck-union.stderr
@@ -0,0 +1,14 @@
+error[E0597]: `v` does not live long enough
+ --> $DIR/dropck-union.rs:37:18
+ |
+LL | v.0.set(Some(&v));
+ | ^^ borrowed value does not live long enough
+LL | }
+ | -
+ | |
+ | `v` dropped here while still borrowed
+ | borrow might be used here, when `v` is dropped and runs the `Drop` code for type `Wrap`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0597`.
diff --git a/src/test/ui/dropck/dropck_fn_type.rs b/src/test/ui/dropck/dropck_fn_type.rs
new file mode 100644
index 000000000..2934217df
--- /dev/null
+++ b/src/test/ui/dropck/dropck_fn_type.rs
@@ -0,0 +1,20 @@
+// run-pass
+//! Regression test for #58311, regarding the usage of Fn types in drop impls
+
+// All of this Drop impls should compile.
+
+#[allow(dead_code)]
+struct S<F: Fn() -> [u8; 1]>(F);
+
+impl<F: Fn() -> [u8; 1]> Drop for S<F> {
+ fn drop(&mut self) {}
+}
+
+#[allow(dead_code)]
+struct P<A, F: FnOnce() -> [A; 10]>(F);
+
+impl<A, F: FnOnce() -> [A; 10]> Drop for P<A, F> {
+ fn drop(&mut self) {}
+}
+
+fn main() {}
diff --git a/src/test/ui/dropck/dropck_no_diverge_on_nonregular_1.rs b/src/test/ui/dropck/dropck_no_diverge_on_nonregular_1.rs
new file mode 100644
index 000000000..43c1c7759
--- /dev/null
+++ b/src/test/ui/dropck/dropck_no_diverge_on_nonregular_1.rs
@@ -0,0 +1,26 @@
+// Issue 22443: Reject code using non-regular types that would
+// otherwise cause dropck to loop infinitely.
+
+use std::marker::PhantomData;
+
+struct Digit<T> {
+ elem: T
+}
+
+struct Node<T:'static> { m: PhantomData<&'static T> }
+
+
+enum FingerTree<T:'static> {
+ Single(T),
+ // Bug report said Digit after Box would stack overflow (versus
+ // Digit before Box; see dropck_no_diverge_on_nonregular_2).
+ Deep(
+ Box<FingerTree<Node<T>>>,
+ Digit<T>,
+ )
+}
+
+fn main() {
+ let ft = //~ ERROR overflow while adding drop-check rules for FingerTree
+ FingerTree::Single(1);
+}
diff --git a/src/test/ui/dropck/dropck_no_diverge_on_nonregular_1.stderr b/src/test/ui/dropck/dropck_no_diverge_on_nonregular_1.stderr
new file mode 100644
index 000000000..c447e2f79
--- /dev/null
+++ b/src/test/ui/dropck/dropck_no_diverge_on_nonregular_1.stderr
@@ -0,0 +1,10 @@
+error[E0320]: overflow while adding drop-check rules for FingerTree<i32>
+ --> $DIR/dropck_no_diverge_on_nonregular_1.rs:24:9
+ |
+LL | let ft =
+ | ^^
+ |
+ = note: overflowed on FingerTree<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<i32>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/dropck/dropck_no_diverge_on_nonregular_2.rs b/src/test/ui/dropck/dropck_no_diverge_on_nonregular_2.rs
new file mode 100644
index 000000000..edd07652e
--- /dev/null
+++ b/src/test/ui/dropck/dropck_no_diverge_on_nonregular_2.rs
@@ -0,0 +1,25 @@
+// Issue 22443: Reject code using non-regular types that would
+// otherwise cause dropck to loop infinitely.
+
+use std::marker::PhantomData;
+
+struct Digit<T> {
+ elem: T
+}
+
+struct Node<T:'static> { m: PhantomData<&'static T> }
+
+enum FingerTree<T:'static> {
+ Single(T),
+ // Bug report said Digit before Box would infinite loop (versus
+ // Digit after Box; see dropck_no_diverge_on_nonregular_1).
+ Deep(
+ Digit<T>,
+ Box<FingerTree<Node<T>>>,
+ )
+}
+
+fn main() {
+ let ft = //~ ERROR overflow while adding drop-check rules for FingerTree
+ FingerTree::Single(1);
+}
diff --git a/src/test/ui/dropck/dropck_no_diverge_on_nonregular_2.stderr b/src/test/ui/dropck/dropck_no_diverge_on_nonregular_2.stderr
new file mode 100644
index 000000000..cd4706dd9
--- /dev/null
+++ b/src/test/ui/dropck/dropck_no_diverge_on_nonregular_2.stderr
@@ -0,0 +1,10 @@
+error[E0320]: overflow while adding drop-check rules for FingerTree<i32>
+ --> $DIR/dropck_no_diverge_on_nonregular_2.rs:23:9
+ |
+LL | let ft =
+ | ^^
+ |
+ = note: overflowed on FingerTree<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<i32>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/dropck/dropck_no_diverge_on_nonregular_3.rs b/src/test/ui/dropck/dropck_no_diverge_on_nonregular_3.rs
new file mode 100644
index 000000000..af7402ca4
--- /dev/null
+++ b/src/test/ui/dropck/dropck_no_diverge_on_nonregular_3.rs
@@ -0,0 +1,35 @@
+// Issue 22443: Reject code using non-regular types that would
+// otherwise cause dropck to loop infinitely.
+//
+// This version is just checking that we still sanely handle a trivial
+// wrapper around the non-regular type. (It also demonstrates how the
+// error messages will report different types depending on which type
+// dropck is analyzing.)
+
+use std::marker::PhantomData;
+
+struct Digit<T> {
+ elem: T
+}
+
+struct Node<T:'static> { m: PhantomData<&'static T> }
+
+enum FingerTree<T:'static> {
+ Single(T),
+ // According to the bug report, Digit before Box would infinite loop.
+ Deep(
+ Digit<T>,
+ Box<FingerTree<Node<T>>>,
+ )
+}
+
+enum Wrapper<T:'static> {
+ Simple,
+ Other(FingerTree<T>),
+}
+
+fn main() {
+ let w = //~ ERROR overflow while adding drop-check rules for Option
+ Some(Wrapper::Simple::<u32>);
+ //~^ ERROR overflow while adding drop-check rules for Wrapper
+}
diff --git a/src/test/ui/dropck/dropck_no_diverge_on_nonregular_3.stderr b/src/test/ui/dropck/dropck_no_diverge_on_nonregular_3.stderr
new file mode 100644
index 000000000..18cd1b6cd
--- /dev/null
+++ b/src/test/ui/dropck/dropck_no_diverge_on_nonregular_3.stderr
@@ -0,0 +1,18 @@
+error[E0320]: overflow while adding drop-check rules for Option<Wrapper<u32>>
+ --> $DIR/dropck_no_diverge_on_nonregular_3.rs:32:9
+ |
+LL | let w =
+ | ^
+ |
+ = note: overflowed on FingerTree<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<u32>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
+
+error[E0320]: overflow while adding drop-check rules for Wrapper<u32>
+ --> $DIR/dropck_no_diverge_on_nonregular_3.rs:33:14
+ |
+LL | Some(Wrapper::Simple::<u32>);
+ | ^^^^^^^^^^^^^^^^^^^^^^
+ |
+ = note: overflowed on FingerTree<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<u32>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
+
+error: aborting due to 2 previous errors
+
diff --git a/src/test/ui/dropck/dropck_trait_cycle_checked.rs b/src/test/ui/dropck/dropck_trait_cycle_checked.rs
new file mode 100644
index 000000000..be6ec3e4e
--- /dev/null
+++ b/src/test/ui/dropck/dropck_trait_cycle_checked.rs
@@ -0,0 +1,121 @@
+// Reject mixing cyclic structure and Drop when using trait
+// objects to hide the cross-references.
+//
+// (Compare against ui/span/dropck_vec_cycle_checked.rs)
+
+use std::cell::Cell;
+use id::Id;
+
+mod s {
+ use std::sync::atomic::{AtomicUsize, Ordering};
+
+ static S_COUNT: AtomicUsize = AtomicUsize::new(0);
+
+ pub fn next_count() -> usize {
+ S_COUNT.fetch_add(1, Ordering::SeqCst) + 1
+ }
+}
+
+mod id {
+ use s;
+ #[derive(Debug)]
+ pub struct Id {
+ orig_count: usize,
+ count: usize,
+ }
+
+ impl Id {
+ pub fn new() -> Id {
+ let c = s::next_count();
+ println!("building Id {}", c);
+ Id { orig_count: c, count: c }
+ }
+ pub fn count(&self) -> usize {
+ println!("Id::count on {} returns {}", self.orig_count, self.count);
+ self.count
+ }
+ }
+
+ impl Drop for Id {
+ fn drop(&mut self) {
+ println!("dropping Id {}", self.count);
+ self.count = 0;
+ }
+ }
+}
+
+trait HasId {
+ fn count(&self) -> usize;
+}
+
+#[derive(Debug)]
+struct CheckId<T:HasId> {
+ v: T
+}
+
+#[allow(non_snake_case)]
+fn CheckId<T:HasId>(t: T) -> CheckId<T> { CheckId{ v: t } }
+
+impl<T:HasId> Drop for CheckId<T> {
+ fn drop(&mut self) {
+ assert!(self.v.count() > 0);
+ }
+}
+
+trait Obj<'a> : HasId {
+ fn set0(&self, b: &'a Box<dyn Obj<'a>>);
+ fn set1(&self, b: &'a Box<dyn Obj<'a>>);
+}
+
+struct O<'a> {
+ id: Id,
+ obj0: CheckId<Cell<Option<&'a Box<dyn Obj<'a>>>>>,
+ obj1: CheckId<Cell<Option<&'a Box<dyn Obj<'a>>>>>,
+}
+
+impl<'a> HasId for O<'a> {
+ fn count(&self) -> usize { self.id.count() }
+}
+
+impl<'a> O<'a> {
+ fn new() -> Box<O<'a>> {
+ Box::new(O {
+ id: Id::new(),
+ obj0: CheckId(Cell::new(None)),
+ obj1: CheckId(Cell::new(None)),
+ })
+ }
+}
+
+impl<'a> HasId for Cell<Option<&'a Box<dyn Obj<'a>>>> {
+ fn count(&self) -> usize {
+ match self.get() {
+ None => 1,
+ Some(c) => c.count(),
+ }
+ }
+}
+
+impl<'a> Obj<'a> for O<'a> {
+ fn set0(&self, b: &'a Box<dyn Obj<'a>>) {
+ self.obj0.v.set(Some(b))
+ }
+ fn set1(&self, b: &'a Box<dyn Obj<'a>>) {
+ self.obj1.v.set(Some(b))
+ }
+}
+
+
+fn f() {
+ let (o1, o2, o3): (Box<dyn Obj>, Box<dyn Obj>, Box<dyn Obj>) = (O::new(), O::new(), O::new());
+ o1.set0(&o2); //~ ERROR `o2` does not live long enough
+ o1.set1(&o3); //~ ERROR `o3` does not live long enough
+ o2.set0(&o2); //~ ERROR `o2` does not live long enough
+ o2.set1(&o3); //~ ERROR `o3` does not live long enough
+ o3.set0(&o1); //~ ERROR `o1` does not live long enough
+ o3.set1(&o2); //~ ERROR `o2` does not live long enough
+}
+
+fn main() {
+ f();
+}
diff --git a/src/test/ui/dropck/dropck_trait_cycle_checked.stderr b/src/test/ui/dropck/dropck_trait_cycle_checked.stderr
new file mode 100644
index 000000000..dc3fbed59
--- /dev/null
+++ b/src/test/ui/dropck/dropck_trait_cycle_checked.stderr
@@ -0,0 +1,73 @@
+error[E0597]: `o2` does not live long enough
+ --> $DIR/dropck_trait_cycle_checked.rs:111:13
+ |
+LL | let (o1, o2, o3): (Box<dyn Obj>, Box<dyn Obj>, Box<dyn Obj>) = (O::new(), O::new(), O::new());
+ | -------- cast requires that `o2` is borrowed for `'static`
+LL | o1.set0(&o2);
+ | ^^^ borrowed value does not live long enough
+...
+LL | }
+ | - `o2` dropped here while still borrowed
+
+error[E0597]: `o3` does not live long enough
+ --> $DIR/dropck_trait_cycle_checked.rs:112:13
+ |
+LL | let (o1, o2, o3): (Box<dyn Obj>, Box<dyn Obj>, Box<dyn Obj>) = (O::new(), O::new(), O::new());
+ | -------- cast requires that `o3` is borrowed for `'static`
+LL | o1.set0(&o2);
+LL | o1.set1(&o3);
+ | ^^^ borrowed value does not live long enough
+...
+LL | }
+ | - `o3` dropped here while still borrowed
+
+error[E0597]: `o2` does not live long enough
+ --> $DIR/dropck_trait_cycle_checked.rs:113:13
+ |
+LL | let (o1, o2, o3): (Box<dyn Obj>, Box<dyn Obj>, Box<dyn Obj>) = (O::new(), O::new(), O::new());
+ | -------- cast requires that `o2` is borrowed for `'static`
+...
+LL | o2.set0(&o2);
+ | ^^^ borrowed value does not live long enough
+...
+LL | }
+ | - `o2` dropped here while still borrowed
+
+error[E0597]: `o3` does not live long enough
+ --> $DIR/dropck_trait_cycle_checked.rs:114:13
+ |
+LL | let (o1, o2, o3): (Box<dyn Obj>, Box<dyn Obj>, Box<dyn Obj>) = (O::new(), O::new(), O::new());
+ | -------- cast requires that `o3` is borrowed for `'static`
+...
+LL | o2.set1(&o3);
+ | ^^^ borrowed value does not live long enough
+...
+LL | }
+ | - `o3` dropped here while still borrowed
+
+error[E0597]: `o1` does not live long enough
+ --> $DIR/dropck_trait_cycle_checked.rs:115:13
+ |
+LL | let (o1, o2, o3): (Box<dyn Obj>, Box<dyn Obj>, Box<dyn Obj>) = (O::new(), O::new(), O::new());
+ | -------- cast requires that `o1` is borrowed for `'static`
+...
+LL | o3.set0(&o1);
+ | ^^^ borrowed value does not live long enough
+LL | o3.set1(&o2);
+LL | }
+ | - `o1` dropped here while still borrowed
+
+error[E0597]: `o2` does not live long enough
+ --> $DIR/dropck_trait_cycle_checked.rs:116:13
+ |
+LL | let (o1, o2, o3): (Box<dyn Obj>, Box<dyn Obj>, Box<dyn Obj>) = (O::new(), O::new(), O::new());
+ | -------- cast requires that `o2` is borrowed for `'static`
+...
+LL | o3.set1(&o2);
+ | ^^^ borrowed value does not live long enough
+LL | }
+ | - `o2` dropped here while still borrowed
+
+error: aborting due to 6 previous errors
+
+For more information about this error, try `rustc --explain E0597`.
diff --git a/src/test/ui/dropck/dropck_traits.rs b/src/test/ui/dropck/dropck_traits.rs
new file mode 100644
index 000000000..98e8e88a2
--- /dev/null
+++ b/src/test/ui/dropck/dropck_traits.rs
@@ -0,0 +1,68 @@
+// run-pass
+//! Regression test for #34426, regarding HRTB in drop impls
+
+// All of this Drop impls should compile.
+
+pub trait Lifetime<'a> {}
+impl<'a> Lifetime<'a> for i32 {}
+
+#[allow(dead_code)]
+struct Foo<L>
+where
+ for<'a> L: Lifetime<'a>,
+{
+ l: L,
+}
+
+impl<L> Drop for Foo<L>
+where
+ for<'a> L: Lifetime<'a>,
+{
+ fn drop(&mut self) {}
+}
+
+#[allow(dead_code)]
+struct Foo2<L>
+where
+ for<'a> L: Lifetime<'a>,
+{
+ l: L,
+}
+
+impl<T: for<'a> Lifetime<'a>> Drop for Foo2<T>
+where
+ for<'x> T: Lifetime<'x>,
+{
+ fn drop(&mut self) {}
+}
+
+pub trait Lifetime2<'a, 'b> {}
+impl<'a, 'b> Lifetime2<'a, 'b> for i32 {}
+
+#[allow(dead_code)]
+struct Bar<L>
+where
+ for<'a, 'b> L: Lifetime2<'a, 'b>,
+{
+ l: L,
+}
+
+impl<L> Drop for Bar<L>
+where
+ for<'a, 'b> L: Lifetime2<'a, 'b>,
+{
+ fn drop(&mut self) {}
+}
+
+#[allow(dead_code)]
+struct FnHolder<T: for<'a> Fn(&'a T, dyn for<'b> Lifetime2<'a, 'b>) -> u8>(T);
+
+impl<T: for<'a> Fn(&'a T, dyn for<'b> Lifetime2<'a, 'b>) -> u8> Drop for FnHolder<T> {
+ fn drop(&mut self) {}
+}
+
+fn main() {
+ let _foo = Foo { l: 0 };
+
+ let _bar = Bar { l: 0 };
+}
diff --git a/src/test/ui/dropck/issue-28498-ugeh-with-lifetime-param.rs b/src/test/ui/dropck/issue-28498-ugeh-with-lifetime-param.rs
new file mode 100644
index 000000000..43c0bfb26
--- /dev/null
+++ b/src/test/ui/dropck/issue-28498-ugeh-with-lifetime-param.rs
@@ -0,0 +1,38 @@
+// run-pass
+
+// Demonstrate the use of the unguarded escape hatch with a lifetime param
+// to assert that destructor will not access any dead data.
+//
+// Compare with ui/span/issue28498-reject-lifetime-param.rs
+
+#![feature(dropck_eyepatch)]
+
+#[derive(Debug)]
+struct ScribbleOnDrop(String);
+
+impl Drop for ScribbleOnDrop {
+ fn drop(&mut self) {
+ self.0 = format!("DROPPED");
+ }
+}
+
+struct Foo<'a>(u32, &'a ScribbleOnDrop);
+
+unsafe impl<#[may_dangle] 'a> Drop for Foo<'a> {
+ fn drop(&mut self) {
+ // Use of `may_dangle` is sound, because destructor never accesses `self.1`.
+ println!("Dropping Foo({}, _)", self.0);
+ }
+}
+
+fn main() {
+ let (last_dropped, foo0);
+ let (foo1, first_dropped);
+
+ last_dropped = ScribbleOnDrop(format!("last"));
+ first_dropped = ScribbleOnDrop(format!("first"));
+ foo0 = Foo(0, &last_dropped);
+ foo1 = Foo(1, &first_dropped);
+
+ println!("foo0.1: {:?} foo1.1: {:?}", foo0.1, foo1.1);
+}
diff --git a/src/test/ui/dropck/issue-28498-ugeh-with-passed-to-fn.rs b/src/test/ui/dropck/issue-28498-ugeh-with-passed-to-fn.rs
new file mode 100644
index 000000000..04d0d3203
--- /dev/null
+++ b/src/test/ui/dropck/issue-28498-ugeh-with-passed-to-fn.rs
@@ -0,0 +1,46 @@
+// run-pass
+
+// Demonstrate the use of the unguarded escape hatch with a type param in negative position
+// to assert that destructor will not access any dead data.
+//
+// Compare with ui/span/issue28498-reject-lifetime-param.rs
+
+// Demonstrate that a type param in negative position causes dropck to reject code
+// that might indirectly access previously dropped value.
+//
+// Compare with run-pass/issue28498-ugeh-with-passed-to-fn.rs
+
+#![feature(dropck_eyepatch)]
+
+#[derive(Debug)]
+struct ScribbleOnDrop(String);
+
+impl Drop for ScribbleOnDrop {
+ fn drop(&mut self) {
+ self.0 = format!("DROPPED");
+ }
+}
+
+struct Foo<T>(u32, T, #[allow(unused_tuple_struct_fields)] Box<for <'r> fn(&'r T) -> String>);
+
+unsafe impl<#[may_dangle] T> Drop for Foo<T> {
+ fn drop(&mut self) {
+ // Use of `may_dangle` is sound, because destructor never passes a `self.1`
+ // to the callback (in `self.2`) despite having it available.
+ println!("Dropping Foo({}, _)", self.0);
+ }
+}
+
+fn callback(s: & &ScribbleOnDrop) -> String { format!("{:?}", s) }
+
+fn main() {
+ let (last_dropped, foo0);
+ let (foo1, first_dropped);
+
+ last_dropped = ScribbleOnDrop(format!("last"));
+ first_dropped = ScribbleOnDrop(format!("first"));
+ foo0 = Foo(0, &last_dropped, Box::new(callback));
+ foo1 = Foo(1, &first_dropped, Box::new(callback));
+
+ println!("foo0.1: {:?} foo1.1: {:?}", foo0.1, foo1.1);
+}
diff --git a/src/test/ui/dropck/issue-28498-ugeh-with-trait-bound.rs b/src/test/ui/dropck/issue-28498-ugeh-with-trait-bound.rs
new file mode 100644
index 000000000..61d11cf38
--- /dev/null
+++ b/src/test/ui/dropck/issue-28498-ugeh-with-trait-bound.rs
@@ -0,0 +1,41 @@
+// run-pass
+
+// Demonstrate the use of the unguarded escape hatch with a trait bound
+// to assert that destructor will not access any dead data.
+//
+// Compare with ui/span/issue28498-reject-trait-bound.rs
+
+#![feature(dropck_eyepatch)]
+
+use std::fmt;
+
+#[derive(Debug)]
+struct ScribbleOnDrop(String);
+
+impl Drop for ScribbleOnDrop {
+ fn drop(&mut self) {
+ self.0 = format!("DROPPED");
+ }
+}
+
+struct Foo<T: fmt::Debug>(u32, T);
+
+unsafe impl<#[may_dangle] T: fmt::Debug> Drop for Foo<T> {
+ fn drop(&mut self) {
+ // Use of `may_dangle` is sound, because destructor never accesses
+ // the `Debug::fmt` method of `T`, despite having it available.
+ println!("Dropping Foo({}, _)", self.0);
+ }
+}
+
+fn main() {
+ let (last_dropped, foo0);
+ let (foo1, first_dropped);
+
+ last_dropped = ScribbleOnDrop(format!("last"));
+ first_dropped = ScribbleOnDrop(format!("first"));
+ foo0 = Foo(0, &last_dropped);
+ foo1 = Foo(1, &first_dropped);
+
+ println!("foo0.1: {:?} foo1.1: {:?}", foo0.1, foo1.1);
+}
diff --git a/src/test/ui/dropck/issue-29844.rs b/src/test/ui/dropck/issue-29844.rs
new file mode 100644
index 000000000..e08942da5
--- /dev/null
+++ b/src/test/ui/dropck/issue-29844.rs
@@ -0,0 +1,24 @@
+// run-pass
+use std::sync::Arc;
+
+pub struct DescriptorSet<'a> {
+ pub slots: Vec<AttachInfo<'a, Resources>>
+}
+
+pub trait ResourcesTrait<'r>: Sized {
+ type DescriptorSet: 'r;
+}
+
+pub struct Resources;
+
+impl<'a> ResourcesTrait<'a> for Resources {
+ type DescriptorSet = DescriptorSet<'a>;
+}
+
+pub enum AttachInfo<'a, R: ResourcesTrait<'a>> {
+ NextDescriptorSet(Arc<R::DescriptorSet>)
+}
+
+fn main() {
+ let _x = DescriptorSet {slots: Vec::new()};
+}
diff --git a/src/test/ui/dropck/issue-38868.rs b/src/test/ui/dropck/issue-38868.rs
new file mode 100644
index 000000000..b0e5c3713
--- /dev/null
+++ b/src/test/ui/dropck/issue-38868.rs
@@ -0,0 +1,13 @@
+pub struct List<T> {
+ head: T,
+}
+
+impl Drop for List<i32> { //~ ERROR E0366
+ fn drop(&mut self) {
+ panic!()
+ }
+}
+
+fn main() {
+ List { head: 0 };
+}
diff --git a/src/test/ui/dropck/issue-38868.stderr b/src/test/ui/dropck/issue-38868.stderr
new file mode 100644
index 000000000..ec81c2ea6
--- /dev/null
+++ b/src/test/ui/dropck/issue-38868.stderr
@@ -0,0 +1,16 @@
+error[E0366]: `Drop` impls cannot be specialized
+ --> $DIR/issue-38868.rs:5:1
+ |
+LL | impl Drop for List<i32> {
+ | ^^^^^^^^^^^^^^^^^^^^^^^
+ |
+ = note: `i32` is not a generic parameter
+note: use the same sequence of generic lifetime, type and const parameters as the struct definition
+ --> $DIR/issue-38868.rs:1:1
+ |
+LL | pub struct List<T> {
+ | ^^^^^^^^^^^^^^^^^^
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0366`.
diff --git a/src/test/ui/dropck/reject-specialized-drops-8142.rs b/src/test/ui/dropck/reject-specialized-drops-8142.rs
new file mode 100644
index 000000000..7a3bbe7cb
--- /dev/null
+++ b/src/test/ui/dropck/reject-specialized-drops-8142.rs
@@ -0,0 +1,75 @@
+// Issue 8142: Test that Drop impls cannot be specialized beyond the
+// predicates attached to the type definition itself.
+trait Bound { fn foo(&self) { } }
+struct K<'l1,'l2> { x: &'l1 i8, y: &'l2 u8 }
+struct L<'l1,'l2> { x: &'l1 i8, y: &'l2 u8 }
+struct M<'m> { x: &'m i8 }
+struct N<'n> { x: &'n i8 }
+struct O<To> { x: *const To }
+struct P<Tp> { x: *const Tp }
+struct Q<Tq> { x: *const Tq }
+struct R<Tr> { x: *const Tr }
+struct S<Ts:Bound> { x: *const Ts }
+struct T<'t,Ts:'t> { x: &'t Ts }
+struct U;
+struct V<Tva, Tvb> { x: *const Tva, y: *const Tvb }
+struct W<'l1, 'l2> { x: &'l1 i8, y: &'l2 u8 }
+struct X<const Ca: usize>;
+struct Y<const Ca: usize, const Cb: usize>;
+
+enum Enum<T> { Variant(T) }
+struct TupleStruct<T>(T);
+union Union<T: Copy> { f: T }
+
+impl<'al,'adds_bnd:'al> Drop for K<'al,'adds_bnd> { // REJECT
+ //~^ ERROR `Drop` impl requires `'adds_bnd: 'al`
+ fn drop(&mut self) { } }
+
+impl<'al,'adds_bnd> Drop for L<'al,'adds_bnd> where 'adds_bnd:'al { // REJECT
+ //~^ ERROR `Drop` impl requires `'adds_bnd: 'al`
+ fn drop(&mut self) { } }
+
+impl<'ml> Drop for M<'ml> { fn drop(&mut self) { } } // ACCEPT
+
+impl Drop for N<'static> { fn drop(&mut self) { } } // REJECT
+//~^ ERROR `Drop` impls cannot be specialized
+
+impl<COkNoBound> Drop for O<COkNoBound> { fn drop(&mut self) { } } // ACCEPT
+
+impl Drop for P<i8> { fn drop(&mut self) { } } // REJECT
+//~^ ERROR `Drop` impls cannot be specialized
+
+impl<AddsBnd:Bound> Drop for Q<AddsBnd> { fn drop(&mut self) { } } // REJECT
+//~^ ERROR `Drop` impl requires `AddsBnd: Bound`
+
+impl<'rbnd,AddsRBnd:'rbnd> Drop for R<AddsRBnd> { fn drop(&mut self) { } } // REJECT
+//~^ ERROR `Drop` impl requires `AddsRBnd: 'rbnd`
+
+impl<Bs:Bound> Drop for S<Bs> { fn drop(&mut self) { } } // ACCEPT
+
+impl<'t,Bt:'t> Drop for T<'t,Bt> { fn drop(&mut self) { } } // ACCEPT
+
+impl Drop for U { fn drop(&mut self) { } } // ACCEPT
+
+impl<One> Drop for V<One,One> { fn drop(&mut self) { } } // REJECT
+//~^ ERROR `Drop` impls cannot be specialized
+
+impl<'lw> Drop for W<'lw,'lw> { fn drop(&mut self) { } } // REJECT
+//~^ ERROR `Drop` impls cannot be specialized
+
+impl Drop for X<3> { fn drop(&mut self) { } } // REJECT
+//~^ ERROR `Drop` impls cannot be specialized
+
+impl<const Ca: usize> Drop for Y<Ca, Ca> { fn drop(&mut self) { } } // REJECT
+//~^ ERROR `Drop` impls cannot be specialized
+
+impl<AddsBnd:Bound> Drop for Enum<AddsBnd> { fn drop(&mut self) { } } // REJECT
+//~^ ERROR `Drop` impl requires `AddsBnd: Bound`
+
+impl<AddsBnd:Bound> Drop for TupleStruct<AddsBnd> { fn drop(&mut self) { } } // REJECT
+//~^ ERROR `Drop` impl requires `AddsBnd: Bound`
+
+impl<AddsBnd:Copy + Bound> Drop for Union<AddsBnd> { fn drop(&mut self) { } } // REJECT
+//~^ ERROR `Drop` impl requires `AddsBnd: Bound`
+
+pub fn main() { }
diff --git a/src/test/ui/dropck/reject-specialized-drops-8142.stderr b/src/test/ui/dropck/reject-specialized-drops-8142.stderr
new file mode 100644
index 000000000..cb48221c6
--- /dev/null
+++ b/src/test/ui/dropck/reject-specialized-drops-8142.stderr
@@ -0,0 +1,166 @@
+error[E0367]: `Drop` impl requires `'adds_bnd: 'al` but the struct it is implemented for does not
+ --> $DIR/reject-specialized-drops-8142.rs:24:20
+ |
+LL | impl<'al,'adds_bnd:'al> Drop for K<'al,'adds_bnd> { // REJECT
+ | ^^^
+ |
+note: the implementor must specify the same requirement
+ --> $DIR/reject-specialized-drops-8142.rs:4:1
+ |
+LL | struct K<'l1,'l2> { x: &'l1 i8, y: &'l2 u8 }
+ | ^^^^^^^^^^^^^^^^^
+
+error[E0367]: `Drop` impl requires `'adds_bnd: 'al` but the struct it is implemented for does not
+ --> $DIR/reject-specialized-drops-8142.rs:28:67
+ |
+LL | impl<'al,'adds_bnd> Drop for L<'al,'adds_bnd> where 'adds_bnd:'al { // REJECT
+ | ^^^
+ |
+note: the implementor must specify the same requirement
+ --> $DIR/reject-specialized-drops-8142.rs:5:1
+ |
+LL | struct L<'l1,'l2> { x: &'l1 i8, y: &'l2 u8 }
+ | ^^^^^^^^^^^^^^^^^
+
+error[E0366]: `Drop` impls cannot be specialized
+ --> $DIR/reject-specialized-drops-8142.rs:34:1
+ |
+LL | impl Drop for N<'static> { fn drop(&mut self) { } } // REJECT
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+ = note: `'static` is not a generic parameter
+note: use the same sequence of generic lifetime, type and const parameters as the struct definition
+ --> $DIR/reject-specialized-drops-8142.rs:7:1
+ |
+LL | struct N<'n> { x: &'n i8 }
+ | ^^^^^^^^^^^^
+
+error[E0366]: `Drop` impls cannot be specialized
+ --> $DIR/reject-specialized-drops-8142.rs:39:1
+ |
+LL | impl Drop for P<i8> { fn drop(&mut self) { } } // REJECT
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+ = note: `i8` is not a generic parameter
+note: use the same sequence of generic lifetime, type and const parameters as the struct definition
+ --> $DIR/reject-specialized-drops-8142.rs:9:1
+ |
+LL | struct P<Tp> { x: *const Tp }
+ | ^^^^^^^^^^^^
+
+error[E0367]: `Drop` impl requires `AddsBnd: Bound` but the struct it is implemented for does not
+ --> $DIR/reject-specialized-drops-8142.rs:42:14
+ |
+LL | impl<AddsBnd:Bound> Drop for Q<AddsBnd> { fn drop(&mut self) { } } // REJECT
+ | ^^^^^
+ |
+note: the implementor must specify the same requirement
+ --> $DIR/reject-specialized-drops-8142.rs:10:1
+ |
+LL | struct Q<Tq> { x: *const Tq }
+ | ^^^^^^^^^^^^
+
+error[E0367]: `Drop` impl requires `AddsRBnd: 'rbnd` but the struct it is implemented for does not
+ --> $DIR/reject-specialized-drops-8142.rs:45:21
+ |
+LL | impl<'rbnd,AddsRBnd:'rbnd> Drop for R<AddsRBnd> { fn drop(&mut self) { } } // REJECT
+ | ^^^^^
+ |
+note: the implementor must specify the same requirement
+ --> $DIR/reject-specialized-drops-8142.rs:11:1
+ |
+LL | struct R<Tr> { x: *const Tr }
+ | ^^^^^^^^^^^^
+
+error[E0366]: `Drop` impls cannot be specialized
+ --> $DIR/reject-specialized-drops-8142.rs:54:1
+ |
+LL | impl<One> Drop for V<One,One> { fn drop(&mut self) { } } // REJECT
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+ = note: `One` is mentioned multiple times
+note: use the same sequence of generic lifetime, type and const parameters as the struct definition
+ --> $DIR/reject-specialized-drops-8142.rs:15:1
+ |
+LL | struct V<Tva, Tvb> { x: *const Tva, y: *const Tvb }
+ | ^^^^^^^^^^^^^^^^^^
+
+error[E0366]: `Drop` impls cannot be specialized
+ --> $DIR/reject-specialized-drops-8142.rs:57:1
+ |
+LL | impl<'lw> Drop for W<'lw,'lw> { fn drop(&mut self) { } } // REJECT
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+ = note: `'lw` is mentioned multiple times
+note: use the same sequence of generic lifetime, type and const parameters as the struct definition
+ --> $DIR/reject-specialized-drops-8142.rs:16:1
+ |
+LL | struct W<'l1, 'l2> { x: &'l1 i8, y: &'l2 u8 }
+ | ^^^^^^^^^^^^^^^^^^
+
+error[E0366]: `Drop` impls cannot be specialized
+ --> $DIR/reject-specialized-drops-8142.rs:60:1
+ |
+LL | impl Drop for X<3> { fn drop(&mut self) { } } // REJECT
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+ = note: `3` is not a generic parameter
+note: use the same sequence of generic lifetime, type and const parameters as the struct definition
+ --> $DIR/reject-specialized-drops-8142.rs:17:1
+ |
+LL | struct X<const Ca: usize>;
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error[E0366]: `Drop` impls cannot be specialized
+ --> $DIR/reject-specialized-drops-8142.rs:63:1
+ |
+LL | impl<const Ca: usize> Drop for Y<Ca, Ca> { fn drop(&mut self) { } } // REJECT
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+ = note: `Ca` is mentioned multiple times
+note: use the same sequence of generic lifetime, type and const parameters as the struct definition
+ --> $DIR/reject-specialized-drops-8142.rs:18:1
+ |
+LL | struct Y<const Ca: usize, const Cb: usize>;
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error[E0367]: `Drop` impl requires `AddsBnd: Bound` but the enum it is implemented for does not
+ --> $DIR/reject-specialized-drops-8142.rs:66:14
+ |
+LL | impl<AddsBnd:Bound> Drop for Enum<AddsBnd> { fn drop(&mut self) { } } // REJECT
+ | ^^^^^
+ |
+note: the implementor must specify the same requirement
+ --> $DIR/reject-specialized-drops-8142.rs:20:1
+ |
+LL | enum Enum<T> { Variant(T) }
+ | ^^^^^^^^^^^^
+
+error[E0367]: `Drop` impl requires `AddsBnd: Bound` but the struct it is implemented for does not
+ --> $DIR/reject-specialized-drops-8142.rs:69:14
+ |
+LL | impl<AddsBnd:Bound> Drop for TupleStruct<AddsBnd> { fn drop(&mut self) { } } // REJECT
+ | ^^^^^
+ |
+note: the implementor must specify the same requirement
+ --> $DIR/reject-specialized-drops-8142.rs:21:1
+ |
+LL | struct TupleStruct<T>(T);
+ | ^^^^^^^^^^^^^^^^^^^^^
+
+error[E0367]: `Drop` impl requires `AddsBnd: Bound` but the union it is implemented for does not
+ --> $DIR/reject-specialized-drops-8142.rs:72:21
+ |
+LL | impl<AddsBnd:Copy + Bound> Drop for Union<AddsBnd> { fn drop(&mut self) { } } // REJECT
+ | ^^^^^
+ |
+note: the implementor must specify the same requirement
+ --> $DIR/reject-specialized-drops-8142.rs:22:1
+ |
+LL | union Union<T: Copy> { f: T }
+ | ^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to 13 previous errors
+
+Some errors have detailed explanations: E0366, E0367.
+For more information about an error, try `rustc --explain E0366`.
diff --git a/src/test/ui/dropck/relate_lt_in_type_outlives_bound.rs b/src/test/ui/dropck/relate_lt_in_type_outlives_bound.rs
new file mode 100644
index 000000000..42530d317
--- /dev/null
+++ b/src/test/ui/dropck/relate_lt_in_type_outlives_bound.rs
@@ -0,0 +1,13 @@
+struct Wrapper<'a, T>(&'a T)
+where
+ T: 'a;
+
+impl<'a, T> Drop for Wrapper<'a, T>
+where
+ T: 'static,
+ //~^ error: `Drop` impl requires `T: 'static` but the struct it is implemented for does not
+{
+ fn drop(&mut self) {}
+}
+
+fn main() {}
diff --git a/src/test/ui/dropck/relate_lt_in_type_outlives_bound.stderr b/src/test/ui/dropck/relate_lt_in_type_outlives_bound.stderr
new file mode 100644
index 000000000..3d9685db6
--- /dev/null
+++ b/src/test/ui/dropck/relate_lt_in_type_outlives_bound.stderr
@@ -0,0 +1,15 @@
+error[E0367]: `Drop` impl requires `T: 'static` but the struct it is implemented for does not
+ --> $DIR/relate_lt_in_type_outlives_bound.rs:7:8
+ |
+LL | T: 'static,
+ | ^^^^^^^
+ |
+note: the implementor must specify the same requirement
+ --> $DIR/relate_lt_in_type_outlives_bound.rs:1:1
+ |
+LL | struct Wrapper<'a, T>(&'a T)
+ | ^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0367`.