From 376a6b2663528b7174472e475a3f4e80ed54e122 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 12 Aug 2018 18:58:08 +0200 Subject: [PATCH] unions are not always trivially dropable Fixes #52786 --- src/librustc/traits/query/dropck_outlives.rs | 8 ++-- src/test/ui/dropck/dropck-union.nll.stderr | 16 ++++++++ src/test/ui/dropck/dropck-union.rs | 40 ++++++++++++++++++++ src/test/ui/dropck/dropck-union.stderr | 13 +++++++ 4 files changed, 72 insertions(+), 5 deletions(-) create mode 100644 src/test/ui/dropck/dropck-union.nll.stderr create mode 100644 src/test/ui/dropck/dropck-union.rs create mode 100644 src/test/ui/dropck/dropck-union.stderr diff --git a/src/librustc/traits/query/dropck_outlives.rs b/src/librustc/traits/query/dropck_outlives.rs index a48d24bb97a..e41ed0824b4 100644 --- a/src/librustc/traits/query/dropck_outlives.rs +++ b/src/librustc/traits/query/dropck_outlives.rs @@ -242,16 +242,14 @@ pub fn trivial_dropck_outlives<'tcx>(tcx: TyCtxt<'_, '_, 'tcx>, ty: Ty<'tcx>) -> .all(|t| trivial_dropck_outlives(tcx, t)), ty::TyAdt(def, _) => { - if def.is_union() { - // Unions never have a dtor. - true - } else if Some(def.did) == tcx.lang_items().manually_drop() { + if Some(def.did) == tcx.lang_items().manually_drop() { // `ManuallyDrop` never has a dtor. true } else { // Other types might. Moreover, PhantomData doesn't // have a dtor, but it is considered to own its - // content, so it is non-trivial. + // content, so it is non-trivial. Unions can have `impl Drop`, + // and hence are non-trivial as well. false } } diff --git a/src/test/ui/dropck/dropck-union.nll.stderr b/src/test/ui/dropck/dropck-union.nll.stderr new file mode 100644 index 00000000000..375ae35af60 --- /dev/null +++ b/src/test/ui/dropck/dropck-union.nll.stderr @@ -0,0 +1,16 @@ +error[E0597]: `v` does not live long enough + --> $DIR/dropck-union.rs:39:18 + | +LL | v.0.set(Some(&v)); //~ ERROR: `v` does not live long enough + | ^^ borrowed value does not live long enough +LL | } + | - + | | + | `v` dropped here while still borrowed + | borrow later used here, when `v` is dropped + | + = note: values in a scope are dropped in the opposite order they are defined + +error: aborting due to previous error + +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 00000000000..ef4d1b360b8 --- /dev/null +++ b/src/test/ui/dropck/dropck-union.rs @@ -0,0 +1,40 @@ +#![feature(untagged_unions)] + +use std::cell::Cell; +use std::ops::Deref; +use std::mem::ManuallyDrop; + +union Wrap { x: ManuallyDrop } + +impl Drop for Wrap { + fn drop(&mut self) { + unsafe { std::ptr::drop_in_place(&mut *self.x as *mut T); } + } +} + +impl Wrap { + fn new(x: T) -> Self { + Wrap { x: ManuallyDrop::new(x) } + } +} + +impl Deref for Wrap { + type Target = T; + #[inline] + fn deref(&self) -> &Self::Target { + unsafe { + &self.x + } + } +} + +struct C<'a>(Cell>>); + +impl<'a> Drop for C<'a> { + fn drop(&mut self) {} +} + +fn main() { + let v : Wrap = 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 00000000000..6cb3c139132 --- /dev/null +++ b/src/test/ui/dropck/dropck-union.stderr @@ -0,0 +1,13 @@ +error[E0597]: `v` does not live long enough + --> $DIR/dropck-union.rs:39:19 + | +LL | v.0.set(Some(&v)); //~ ERROR: `v` does not live long enough + | ^ borrowed value does not live long enough +LL | } + | - `v` dropped here while still borrowed + | + = note: values in a scope are dropped in the opposite order they are created + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0597`.