diff --git a/src/librustc_mir/diagnostics.rs b/src/librustc_mir/diagnostics.rs index 83a8ce34c6928..4b71a429f847a 100644 --- a/src/librustc_mir/diagnostics.rs +++ b/src/librustc_mir/diagnostics.rs @@ -431,29 +431,6 @@ Remember this solution is unsafe! You will have to ensure that accesses to the cell are synchronized. "##, -E0493: r##" -A type with a destructor was assigned to an invalid type of variable. Erroneous -code example: - -```compile_fail,E0493 -struct Foo { - a: u32 -} - -impl Drop for Foo { - fn drop(&mut self) {} -} - -const F : Foo = Foo { a : 0 }; -// error: constants are not allowed to have destructors -static S : Foo = Foo { a : 0 }; -// error: destructors in statics are an unstable feature -``` - -To solve this issue, please use a type which does allow the usage of type with -destructors. -"##, - E0494: r##" A reference of an interior static was assigned to another const/static. Erroneous code example: @@ -991,6 +968,7 @@ fn print_fancy_ref(fancy_ref: &FancyNum){ } register_diagnostics! { + E0493, // destructors cannot be evaluated at compile-time E0524, // two closures require unique access to `..` at the same time E0526, // shuffle indices are not constant E0625, // thread-local statics cannot be accessed at compile-time diff --git a/src/librustc_mir/transform/qualify_consts.rs b/src/librustc_mir/transform/qualify_consts.rs index f891c991321c8..1a5832d10f4a2 100644 --- a/src/librustc_mir/transform/qualify_consts.rs +++ b/src/librustc_mir/transform/qualify_consts.rs @@ -18,7 +18,6 @@ use rustc_data_structures::bitvec::BitVector; use rustc_data_structures::indexed_set::IdxSetBuf; use rustc_data_structures::indexed_vec::{IndexVec, Idx}; use rustc::hir; -use rustc::hir::map as hir_map; use rustc::hir::def_id::DefId; use rustc::traits::{self, Reveal}; use rustc::ty::{self, TyCtxt, Ty, TypeFoldable}; @@ -196,91 +195,6 @@ impl<'a, 'tcx> Qualifier<'a, 'tcx, 'tcx> { self.add(original); } - /// Check for NEEDS_DROP (from an ADT or const fn call) and - /// error, unless we're in a function. - fn always_deny_drop(&self) { - self.deny_drop_with_feature_gate_override(false); - } - - /// Check for NEEDS_DROP (from an ADT or const fn call) and - /// error, unless we're in a function, or the feature-gate - /// for constant with destructors is enabled. - fn deny_drop(&self) { - self.deny_drop_with_feature_gate_override(true); - } - - fn deny_drop_with_feature_gate_override(&self, allow_gate: bool) { - if self.mode == Mode::Fn || !self.qualif.intersects(Qualif::NEEDS_DROP) { - return; - } - - // Constants allow destructors, but they're feature-gated. - let msg = if allow_gate { - // Feature-gate for constant with destructors is enabled. - if self.tcx.sess.features.borrow().drop_types_in_const { - return; - } - - // This comes from a macro that has #[allow_internal_unstable]. - if self.span.allows_unstable() { - return; - } - - format!("destructors in {}s are an unstable feature", - self.mode) - } else { - format!("{}s are not allowed to have destructors", - self.mode) - }; - - let mut err = - struct_span_err!(self.tcx.sess, self.span, E0493, "{}", msg); - - if allow_gate { - help!(&mut err, - "in Nightly builds, add `#![feature(drop_types_in_const)]` \ - to the crate attributes to enable"); - } else { - // FIXME(eddyb) this looks up `self.mir.return_ty`. - // We probably want the actual return type here, if at all. - self.find_drop_implementation_method_span() - .map(|span| err.span_label(span, "destructor defined here")); - - err.span_label(self.span, - format!("{}s cannot have destructors", self.mode)); - } - - err.emit(); - } - - fn find_drop_implementation_method_span(&self) -> Option { - self.tcx.lang_items() - .drop_trait() - .and_then(|drop_trait_id| { - let mut span = None; - - self.tcx - .for_each_relevant_impl(drop_trait_id, self.mir.return_ty, |impl_did| { - self.tcx.hir - .as_local_node_id(impl_did) - .and_then(|impl_node_id| self.tcx.hir.find(impl_node_id)) - .map(|node| { - if let hir_map::NodeItem(item) = node { - if let hir::ItemImpl(.., ref impl_item_refs) = item.node { - span = impl_item_refs.first() - .map(|iiref| { - self.tcx.hir.impl_item(iiref.id) - .span - }); - } - } - }); - }); - - span - }) - } - /// Check if an Lvalue with the current qualifications could /// be consumed, by either an operand or a Deref projection. fn try_consume(&mut self) -> bool { @@ -457,25 +371,17 @@ impl<'a, 'tcx> Qualifier<'a, 'tcx, 'tcx> { } } - let return_ty = mir.return_ty; self.qualif = self.return_qualif.unwrap_or(Qualif::NOT_CONST); - match self.mode { - Mode::StaticMut => { - // Check for destructors in static mut. - self.add_type(return_ty); - self.deny_drop(); - } - _ => { - // Account for errors in consts by using the - // conservative type qualification instead. - if self.qualif.intersects(Qualif::CONST_ERROR) { - self.qualif = Qualif::empty(); - self.add_type(return_ty); - } - } + // Account for errors in consts by using the + // conservative type qualification instead. + if self.qualif.intersects(Qualif::CONST_ERROR) { + self.qualif = Qualif::empty(); + let return_ty = mir.return_ty; + self.add_type(return_ty); } + // Collect all the temps we need to promote. let mut promoted_temps = IdxSetBuf::new_empty(self.temp_promotion_state.len()); @@ -637,12 +543,6 @@ impl<'a, 'tcx> Visitor<'tcx> for Qualifier<'a, 'tcx, 'tcx> { // with type parameters, take it into account. self.qualif.restrict(constant.ty, self.tcx, self.param_env); } - - // Let `const fn` transitively have destructors, - // but they do get stopped in `const` or `static`. - if self.mode != Mode::ConstFn { - self.deny_drop(); - } } } } @@ -687,12 +587,7 @@ impl<'a, 'tcx> Visitor<'tcx> for Qualifier<'a, 'tcx, 'tcx> { let allow = if self.mode == Mode::StaticMut { // Inside a `static mut`, &mut [...] is also allowed. match ty.sty { - ty::TyArray(..) | ty::TySlice(_) => { - // Mutating can expose drops, be conservative. - self.add_type(ty); - self.deny_drop(); - true - } + ty::TyArray(..) | ty::TySlice(_) => true, _ => false } } else if let ty::TyArray(_, 0) = ty.sty { @@ -794,18 +689,12 @@ impl<'a, 'tcx> Visitor<'tcx> for Qualifier<'a, 'tcx, 'tcx> { if let AggregateKind::Adt(def, ..) = **kind { if def.has_dtor(self.tcx) { self.add(Qualif::NEEDS_DROP); - self.deny_drop(); } if Some(def.did) == self.tcx.lang_items().unsafe_cell_type() { let ty = rvalue.ty(self.mir, self.tcx); self.add_type(ty); assert!(self.qualif.intersects(Qualif::MUTABLE_INTERIOR)); - // Even if the value inside may not need dropping, - // mutating it would change that. - if !self.qualif.intersects(Qualif::NOT_CONST) { - self.deny_drop(); - } } } } @@ -915,12 +804,6 @@ impl<'a, 'tcx> Visitor<'tcx> for Qualifier<'a, 'tcx, 'tcx> { let ty = dest.ty(self.mir, tcx).to_ty(tcx); self.qualif = Qualif::empty(); self.add_type(ty); - - // Let `const fn` transitively have destructors, - // but they do get stopped in `const` or `static`. - if self.mode != Mode::ConstFn { - self.deny_drop(); - } } self.assign(dest, location); } @@ -938,14 +821,15 @@ impl<'a, 'tcx> Visitor<'tcx> for Qualifier<'a, 'tcx, 'tcx> { }; if let Some(span) = needs_drop { + // Double-check the type being dropped, to minimize false positives. let ty = lvalue.ty(self.mir, self.tcx).to_ty(self.tcx); - self.add_type(ty); - - // Use the original assignment span to be more precise. - let old_span = self.span; - self.span = span; - self.always_deny_drop(); - self.span = old_span; + if ty.needs_drop(self.tcx, self.param_env) { + struct_span_err!(self.tcx.sess, span, E0493, + "destructors cannot be evaluated at compile-time") + .span_label(span, format!("{}s cannot evaluate destructors", + self.mode)) + .emit(); + } } } } else { diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs index 54d41a030fd77..e3da9641cae54 100644 --- a/src/libsyntax/feature_gate.rs +++ b/src/libsyntax/feature_gate.rs @@ -269,9 +269,6 @@ declare_features! ( // impl specialization (RFC 1210) (active, specialization, "1.7.0", Some(31844)), - // Allow Drop types in statics/const functions (RFC 1440) - (active, drop_types_in_const, "1.9.0", Some(33156)), - // Allows cfg(target_has_atomic = "..."). (active, cfg_target_has_atomic, "1.9.0", Some(32976)), @@ -466,6 +463,8 @@ declare_features! ( (accepted, compile_error, "1.20.0", Some(40872)), // See rust-lang/rfcs#1414. Allows code like `let x: &'static u32 = &42` to work. (accepted, rvalue_static_promotion, "1.21.0", Some(38865)), + // Allow Drop types in constants (RFC 1440) + (accepted, drop_types_in_const, "1.22.0", Some(33156)), ); // If you change this, please modify src/doc/unstable-book as well. You must diff --git a/src/test/compile-fail/check-static-values-constraints.rs b/src/test/compile-fail/check-static-values-constraints.rs index c349aababd6c0..37f665960c8c8 100644 --- a/src/test/compile-fail/check-static-values-constraints.rs +++ b/src/test/compile-fail/check-static-values-constraints.rs @@ -10,8 +10,6 @@ // Verifies all possible restrictions for statics values. -// gate-test-drop_types_in_const - #![allow(warnings)] #![feature(box_syntax)] @@ -37,15 +35,8 @@ enum SafeEnum { // These should be ok static STATIC1: SafeEnum = SafeEnum::Variant1; static STATIC2: SafeEnum = SafeEnum::Variant2(0); - -// This one should fail static STATIC3: SafeEnum = SafeEnum::Variant3(WithDtor); -//~^ ERROR destructors in statics are an unstable feature - -// This enum will be used to test that variants -// are considered unsafe if their enum type implements -// a destructor. enum UnsafeEnum { Variant5, Variant6(isize) @@ -57,9 +48,7 @@ impl Drop for UnsafeEnum { static STATIC4: UnsafeEnum = UnsafeEnum::Variant5; -//~^ ERROR destructors in statics are an unstable feature static STATIC5: UnsafeEnum = UnsafeEnum::Variant6(0); -//~^ ERROR destructors in statics are an unstable feature struct SafeStruct { @@ -71,10 +60,8 @@ struct SafeStruct { // Struct fields are safe, hence this static should be safe static STATIC6: SafeStruct = SafeStruct{field1: SafeEnum::Variant1, field2: SafeEnum::Variant2(0)}; -// field2 has an unsafe value, hence this should fail static STATIC7: SafeStruct = SafeStruct{field1: SafeEnum::Variant1, field2: SafeEnum::Variant3(WithDtor)}; -//~^ ERROR destructors in statics are an unstable feature // Test variadic constructor for structs. The base struct should be examined // as well as every field present in the constructor. @@ -86,8 +73,7 @@ static STATIC8: SafeStruct = SafeStruct{field1: SafeEnum::Variant1, // This example should fail because field1 in the base struct is not safe static STATIC9: SafeStruct = SafeStruct{field1: SafeEnum::Variant1, ..SafeStruct{field1: SafeEnum::Variant3(WithDtor), -//~^ ERROR destructors in statics are an unstable feature -//~| ERROR statics are not allowed to have destructors +//~^ ERROR destructors cannot be evaluated at compile-time field2: SafeEnum::Variant1}}; struct UnsafeStruct; @@ -96,29 +82,19 @@ impl Drop for UnsafeStruct { fn drop(&mut self) {} } -// Types with destructors are not allowed for statics static STATIC10: UnsafeStruct = UnsafeStruct; -//~^ ERROR destructors in statics are an unstable feature struct MyOwned; static STATIC11: Box = box MyOwned; //~^ ERROR allocations are not allowed in statics -// The following examples test that mutable structs are just forbidden -// to have types with destructors -// These should fail static mut STATIC12: UnsafeStruct = UnsafeStruct; -//~^ ERROR destructors in statics are an unstable feature -//~^^ ERROR destructors in statics are an unstable feature static mut STATIC13: SafeStruct = SafeStruct{field1: SafeEnum::Variant1, -//~^ ERROR destructors in statics are an unstable feature field2: SafeEnum::Variant3(WithDtor)}; -//~^ ERROR: destructors in statics are an unstable feature static mut STATIC14: SafeStruct = SafeStruct { -//~^ ERROR destructors in statics are an unstable feature field1: SafeEnum::Variant1, field2: SafeEnum::Variant4("str".to_string()) //~^ ERROR calls in statics are limited to constant functions @@ -135,7 +111,6 @@ static STATIC16: (&'static Box, &'static Box) = ( ); static mut STATIC17: SafeEnum = SafeEnum::Variant1; -//~^ ERROR destructors in statics are an unstable feature static STATIC19: Box = box 3; diff --git a/src/test/compile-fail/issue-43733-2.rs b/src/test/compile-fail/issue-43733-2.rs index 3dff34c2ebb12..0fd31454596e6 100644 --- a/src/test/compile-fail/issue-43733-2.rs +++ b/src/test/compile-fail/issue-43733-2.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![feature(const_fn, drop_types_in_const)] +#![feature(const_fn)] #![feature(cfg_target_thread_local, thread_local_internals)] // On platforms *without* `#[thread_local]`, use diff --git a/src/test/compile-fail/issue-43733.rs b/src/test/compile-fail/issue-43733.rs index a4aad21a9f832..f10531e407d62 100644 --- a/src/test/compile-fail/issue-43733.rs +++ b/src/test/compile-fail/issue-43733.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![feature(const_fn, drop_types_in_const)] +#![feature(const_fn)] #![feature(cfg_target_thread_local, thread_local_internals)] type Foo = std::cell::RefCell; diff --git a/src/test/compile-fail/static-drop-scope.rs b/src/test/compile-fail/static-drop-scope.rs index f8fdf8c45cbdb..c96cadece97a5 100644 --- a/src/test/compile-fail/static-drop-scope.rs +++ b/src/test/compile-fail/static-drop-scope.rs @@ -8,8 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![feature(drop_types_in_const)] - struct WithDtor; impl Drop for WithDtor { @@ -17,17 +15,17 @@ impl Drop for WithDtor { } static PROMOTION_FAIL_S: Option<&'static WithDtor> = Some(&WithDtor); -//~^ ERROR statics are not allowed to have destructors +//~^ ERROR destructors cannot be evaluated at compile-time //~| ERROR borrowed value does not live long enoug const PROMOTION_FAIL_C: Option<&'static WithDtor> = Some(&WithDtor); -//~^ ERROR constants are not allowed to have destructors +//~^ ERROR destructors cannot be evaluated at compile-time //~| ERROR borrowed value does not live long enoug static EARLY_DROP_S: i32 = (WithDtor, 0).1; -//~^ ERROR statics are not allowed to have destructors +//~^ ERROR destructors cannot be evaluated at compile-time const EARLY_DROP_C: i32 = (WithDtor, 0).1; -//~^ ERROR constants are not allowed to have destructors +//~^ ERROR destructors cannot be evaluated at compile-time fn main () {} diff --git a/src/test/compile-fail/static-mut-not-constant.rs b/src/test/compile-fail/static-mut-not-constant.rs index a855b08f06691..5cc3384f554d3 100644 --- a/src/test/compile-fail/static-mut-not-constant.rs +++ b/src/test/compile-fail/static-mut-not-constant.rs @@ -8,13 +8,10 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// gate-test-drop_types_in_const - #![feature(box_syntax)] static mut a: Box = box 3; //~^ ERROR allocations are not allowed in statics -//~| ERROR destructors in statics are an unstable feature //~| WARN: constant evaluation error fn main() {} diff --git a/src/test/compile-fail/issue-17718-const-destructors.rs b/src/test/run-pass/issue-17718-const-destructors.rs similarity index 90% rename from src/test/compile-fail/issue-17718-const-destructors.rs rename to src/test/run-pass/issue-17718-const-destructors.rs index 6c2eafe040a36..ca0b222050e21 100644 --- a/src/test/compile-fail/issue-17718-const-destructors.rs +++ b/src/test/run-pass/issue-17718-const-destructors.rs @@ -14,6 +14,5 @@ impl Drop for A { } const FOO: A = A; -//~^ ERROR: destructors in constants are an unstable feature fn main() {} diff --git a/src/test/run-pass/issue-34053.rs b/src/test/run-pass/issue-34053.rs index c085ee7d46ac3..81c4552414752 100644 --- a/src/test/run-pass/issue-34053.rs +++ b/src/test/run-pass/issue-34053.rs @@ -8,8 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![feature(drop_types_in_const)] - use std::sync::atomic::{AtomicUsize, ATOMIC_USIZE_INIT, Ordering}; static DROP_COUNTER: AtomicUsize = ATOMIC_USIZE_INIT; diff --git a/src/test/compile-fail/issue-9243.rs b/src/test/run-pass/issue-9243.rs similarity index 91% rename from src/test/compile-fail/issue-9243.rs rename to src/test/run-pass/issue-9243.rs index 58bdff6c0414b..b857465aabc1d 100644 --- a/src/test/compile-fail/issue-9243.rs +++ b/src/test/run-pass/issue-9243.rs @@ -15,7 +15,6 @@ pub struct Test { } pub static g_test: Test = Test {mem: 0}; -//~^ ERROR destructors in statics are an unstable feature impl Drop for Test { fn drop(&mut self) {} diff --git a/src/test/run-pass/union/union-nodrop.rs b/src/test/run-pass/union/union-nodrop.rs index 22f00be3066dc..6295c6120c5ba 100644 --- a/src/test/run-pass/union/union-nodrop.rs +++ b/src/test/run-pass/union/union-nodrop.rs @@ -16,9 +16,15 @@ use std::intrinsics::needs_drop; -// drop types in destructors should not require -// drop_types_in_const -static X: Option>> = None; +struct NeedDrop; + +impl Drop for NeedDrop { + fn drop(&mut self) {} +} + +// Constant expressios allow `NoDrop` to go out of scope, +// unlike a value of the interior type implementing `Drop`. +static X: () = (NoDrop { inner: NeedDrop }, ()).1; // A union that scrubs the drop glue from its inner type union NoDrop {inner: T} diff --git a/src/test/ui/span/E0493.rs b/src/test/ui/span/E0493.rs index eae871d2d4e46..7915564cafb0a 100644 --- a/src/test/ui/span/E0493.rs +++ b/src/test/ui/span/E0493.rs @@ -8,8 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![feature(drop_types_in_const)] - struct Foo { a: u32 } diff --git a/src/test/ui/span/E0493.stderr b/src/test/ui/span/E0493.stderr index 8da11fefc177a..d7996eaef3a4b 100644 --- a/src/test/ui/span/E0493.stderr +++ b/src/test/ui/span/E0493.stderr @@ -1,11 +1,8 @@ -error[E0493]: constants are not allowed to have destructors - --> $DIR/E0493.rs:29:17 +error[E0493]: destructors cannot be evaluated at compile-time + --> $DIR/E0493.rs:27:17 | -18 | fn drop(&mut self) {} - | --------------------- destructor defined here -... -29 | const F : Foo = (Foo { a : 0 }, Foo { a : 1 }).1; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constants cannot have destructors +27 | const F : Foo = (Foo { a : 0 }, Foo { a : 1 }).1; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constants cannot evaluate destructors error: aborting due to previous error