diff options
Diffstat (limited to 'src/test/ui/dropck')
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`. |