Skip to content

Commit 7eefed3

Browse files
committed
Auto merge of #44456 - eddyb:stable-drop-const, r=nikomatsakis
Stabilize drop_types_in_const. Closes #33156, stabilizing the new, revised, rules, and improving the error message. r? @nikomatsakis cc @SergioBenitez
2 parents 2fdccaf + 5601ae4 commit 7eefed3

14 files changed

+39
-211
lines changed

src/librustc_mir/diagnostics.rs

+1-23
Original file line numberDiff line numberDiff line change
@@ -431,29 +431,6 @@ Remember this solution is unsafe! You will have to ensure that accesses to the
431431
cell are synchronized.
432432
"##,
433433

434-
E0493: r##"
435-
A type with a destructor was assigned to an invalid type of variable. Erroneous
436-
code example:
437-
438-
```compile_fail,E0493
439-
struct Foo {
440-
a: u32
441-
}
442-
443-
impl Drop for Foo {
444-
fn drop(&mut self) {}
445-
}
446-
447-
const F : Foo = Foo { a : 0 };
448-
// error: constants are not allowed to have destructors
449-
static S : Foo = Foo { a : 0 };
450-
// error: destructors in statics are an unstable feature
451-
```
452-
453-
To solve this issue, please use a type which does allow the usage of type with
454-
destructors.
455-
"##,
456-
457434
E0494: r##"
458435
A reference of an interior static was assigned to another const/static.
459436
Erroneous code example:
@@ -991,6 +968,7 @@ fn print_fancy_ref(fancy_ref: &FancyNum){
991968
}
992969

993970
register_diagnostics! {
971+
E0493, // destructors cannot be evaluated at compile-time
994972
E0524, // two closures require unique access to `..` at the same time
995973
E0526, // shuffle indices are not constant
996974
E0625, // thread-local statics cannot be accessed at compile-time

src/librustc_mir/transform/qualify_consts.rs

+16-132
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,6 @@ use rustc_data_structures::bitvec::BitVector;
1818
use rustc_data_structures::indexed_set::IdxSetBuf;
1919
use rustc_data_structures::indexed_vec::{IndexVec, Idx};
2020
use rustc::hir;
21-
use rustc::hir::map as hir_map;
2221
use rustc::hir::def_id::DefId;
2322
use rustc::middle::const_val::ConstVal;
2423
use rustc::traits::{self, Reveal};
@@ -197,91 +196,6 @@ impl<'a, 'tcx> Qualifier<'a, 'tcx, 'tcx> {
197196
self.add(original);
198197
}
199198

200-
/// Check for NEEDS_DROP (from an ADT or const fn call) and
201-
/// error, unless we're in a function.
202-
fn always_deny_drop(&self) {
203-
self.deny_drop_with_feature_gate_override(false);
204-
}
205-
206-
/// Check for NEEDS_DROP (from an ADT or const fn call) and
207-
/// error, unless we're in a function, or the feature-gate
208-
/// for constant with destructors is enabled.
209-
fn deny_drop(&self) {
210-
self.deny_drop_with_feature_gate_override(true);
211-
}
212-
213-
fn deny_drop_with_feature_gate_override(&self, allow_gate: bool) {
214-
if self.mode == Mode::Fn || !self.qualif.intersects(Qualif::NEEDS_DROP) {
215-
return;
216-
}
217-
218-
// Constants allow destructors, but they're feature-gated.
219-
let msg = if allow_gate {
220-
// Feature-gate for constant with destructors is enabled.
221-
if self.tcx.sess.features.borrow().drop_types_in_const {
222-
return;
223-
}
224-
225-
// This comes from a macro that has #[allow_internal_unstable].
226-
if self.span.allows_unstable() {
227-
return;
228-
}
229-
230-
format!("destructors in {}s are an unstable feature",
231-
self.mode)
232-
} else {
233-
format!("{}s are not allowed to have destructors",
234-
self.mode)
235-
};
236-
237-
let mut err =
238-
struct_span_err!(self.tcx.sess, self.span, E0493, "{}", msg);
239-
240-
if allow_gate {
241-
help!(&mut err,
242-
"in Nightly builds, add `#![feature(drop_types_in_const)]` \
243-
to the crate attributes to enable");
244-
} else {
245-
// FIXME(eddyb) this looks up `self.mir.return_ty`.
246-
// We probably want the actual return type here, if at all.
247-
self.find_drop_implementation_method_span()
248-
.map(|span| err.span_label(span, "destructor defined here"));
249-
250-
err.span_label(self.span,
251-
format!("{}s cannot have destructors", self.mode));
252-
}
253-
254-
err.emit();
255-
}
256-
257-
fn find_drop_implementation_method_span(&self) -> Option<Span> {
258-
self.tcx.lang_items()
259-
.drop_trait()
260-
.and_then(|drop_trait_id| {
261-
let mut span = None;
262-
263-
self.tcx
264-
.for_each_relevant_impl(drop_trait_id, self.mir.return_ty, |impl_did| {
265-
self.tcx.hir
266-
.as_local_node_id(impl_did)
267-
.and_then(|impl_node_id| self.tcx.hir.find(impl_node_id))
268-
.map(|node| {
269-
if let hir_map::NodeItem(item) = node {
270-
if let hir::ItemImpl(.., ref impl_item_refs) = item.node {
271-
span = impl_item_refs.first()
272-
.map(|iiref| {
273-
self.tcx.hir.impl_item(iiref.id)
274-
.span
275-
});
276-
}
277-
}
278-
});
279-
});
280-
281-
span
282-
})
283-
}
284-
285199
/// Check if an Lvalue with the current qualifications could
286200
/// be consumed, by either an operand or a Deref projection.
287201
fn try_consume(&mut self) -> bool {
@@ -458,25 +372,17 @@ impl<'a, 'tcx> Qualifier<'a, 'tcx, 'tcx> {
458372
}
459373
}
460374

461-
let return_ty = mir.return_ty;
462375
self.qualif = self.return_qualif.unwrap_or(Qualif::NOT_CONST);
463376

464-
match self.mode {
465-
Mode::StaticMut => {
466-
// Check for destructors in static mut.
467-
self.add_type(return_ty);
468-
self.deny_drop();
469-
}
470-
_ => {
471-
// Account for errors in consts by using the
472-
// conservative type qualification instead.
473-
if self.qualif.intersects(Qualif::CONST_ERROR) {
474-
self.qualif = Qualif::empty();
475-
self.add_type(return_ty);
476-
}
477-
}
377+
// Account for errors in consts by using the
378+
// conservative type qualification instead.
379+
if self.qualif.intersects(Qualif::CONST_ERROR) {
380+
self.qualif = Qualif::empty();
381+
let return_ty = mir.return_ty;
382+
self.add_type(return_ty);
478383
}
479384

385+
480386
// Collect all the temps we need to promote.
481387
let mut promoted_temps = IdxSetBuf::new_empty(self.temp_promotion_state.len());
482388

@@ -640,12 +546,6 @@ impl<'a, 'tcx> Visitor<'tcx> for Qualifier<'a, 'tcx, 'tcx> {
640546
// with type parameters, take it into account.
641547
self.qualif.restrict(ty, self.tcx, self.param_env);
642548
}
643-
644-
// Let `const fn` transitively have destructors,
645-
// but they do get stopped in `const` or `static`.
646-
if self.mode != Mode::ConstFn {
647-
self.deny_drop();
648-
}
649549
}
650550
}
651551
}
@@ -690,12 +590,7 @@ impl<'a, 'tcx> Visitor<'tcx> for Qualifier<'a, 'tcx, 'tcx> {
690590
let allow = if self.mode == Mode::StaticMut {
691591
// Inside a `static mut`, &mut [...] is also allowed.
692592
match ty.sty {
693-
ty::TyArray(..) | ty::TySlice(_) => {
694-
// Mutating can expose drops, be conservative.
695-
self.add_type(ty);
696-
self.deny_drop();
697-
true
698-
}
593+
ty::TyArray(..) | ty::TySlice(_) => true,
699594
_ => false
700595
}
701596
} else if let ty::TyArray(_, len) = ty.sty {
@@ -798,18 +693,12 @@ impl<'a, 'tcx> Visitor<'tcx> for Qualifier<'a, 'tcx, 'tcx> {
798693
if let AggregateKind::Adt(def, ..) = **kind {
799694
if def.has_dtor(self.tcx) {
800695
self.add(Qualif::NEEDS_DROP);
801-
self.deny_drop();
802696
}
803697

804698
if Some(def.did) == self.tcx.lang_items().unsafe_cell_type() {
805699
let ty = rvalue.ty(self.mir, self.tcx);
806700
self.add_type(ty);
807701
assert!(self.qualif.intersects(Qualif::MUTABLE_INTERIOR));
808-
// Even if the value inside may not need dropping,
809-
// mutating it would change that.
810-
if !self.qualif.intersects(Qualif::NOT_CONST) {
811-
self.deny_drop();
812-
}
813702
}
814703
}
815704
}
@@ -919,12 +808,6 @@ impl<'a, 'tcx> Visitor<'tcx> for Qualifier<'a, 'tcx, 'tcx> {
919808
let ty = dest.ty(self.mir, tcx).to_ty(tcx);
920809
self.qualif = Qualif::empty();
921810
self.add_type(ty);
922-
923-
// Let `const fn` transitively have destructors,
924-
// but they do get stopped in `const` or `static`.
925-
if self.mode != Mode::ConstFn {
926-
self.deny_drop();
927-
}
928811
}
929812
self.assign(dest, location);
930813
}
@@ -942,14 +825,15 @@ impl<'a, 'tcx> Visitor<'tcx> for Qualifier<'a, 'tcx, 'tcx> {
942825
};
943826

944827
if let Some(span) = needs_drop {
828+
// Double-check the type being dropped, to minimize false positives.
945829
let ty = lvalue.ty(self.mir, self.tcx).to_ty(self.tcx);
946-
self.add_type(ty);
947-
948-
// Use the original assignment span to be more precise.
949-
let old_span = self.span;
950-
self.span = span;
951-
self.always_deny_drop();
952-
self.span = old_span;
830+
if ty.needs_drop(self.tcx, self.param_env) {
831+
struct_span_err!(self.tcx.sess, span, E0493,
832+
"destructors cannot be evaluated at compile-time")
833+
.span_label(span, format!("{}s cannot evaluate destructors",
834+
self.mode))
835+
.emit();
836+
}
953837
}
954838
}
955839
} else {

src/libsyntax/feature_gate.rs

+2-3
Original file line numberDiff line numberDiff line change
@@ -269,9 +269,6 @@ declare_features! (
269269
// impl specialization (RFC 1210)
270270
(active, specialization, "1.7.0", Some(31844)),
271271

272-
// Allow Drop types in statics/const functions (RFC 1440)
273-
(active, drop_types_in_const, "1.9.0", Some(33156)),
274-
275272
// Allows cfg(target_has_atomic = "...").
276273
(active, cfg_target_has_atomic, "1.9.0", Some(32976)),
277274

@@ -469,6 +466,8 @@ declare_features! (
469466
(accepted, compile_error, "1.20.0", Some(40872)),
470467
// See rust-lang/rfcs#1414. Allows code like `let x: &'static u32 = &42` to work.
471468
(accepted, rvalue_static_promotion, "1.21.0", Some(38865)),
469+
// Allow Drop types in constants (RFC 1440)
470+
(accepted, drop_types_in_const, "1.22.0", Some(33156)),
472471
);
473472

474473
// If you change this, please modify src/doc/unstable-book as well. You must

src/test/compile-fail/check-static-values-constraints.rs

+1-26
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,6 @@
1010

1111
// Verifies all possible restrictions for statics values.
1212

13-
// gate-test-drop_types_in_const
14-
1513
#![allow(warnings)]
1614
#![feature(box_syntax)]
1715

@@ -37,15 +35,8 @@ enum SafeEnum {
3735
// These should be ok
3836
static STATIC1: SafeEnum = SafeEnum::Variant1;
3937
static STATIC2: SafeEnum = SafeEnum::Variant2(0);
40-
41-
// This one should fail
4238
static STATIC3: SafeEnum = SafeEnum::Variant3(WithDtor);
43-
//~^ ERROR destructors in statics are an unstable feature
44-
4539

46-
// This enum will be used to test that variants
47-
// are considered unsafe if their enum type implements
48-
// a destructor.
4940
enum UnsafeEnum {
5041
Variant5,
5142
Variant6(isize)
@@ -57,9 +48,7 @@ impl Drop for UnsafeEnum {
5748

5849

5950
static STATIC4: UnsafeEnum = UnsafeEnum::Variant5;
60-
//~^ ERROR destructors in statics are an unstable feature
6151
static STATIC5: UnsafeEnum = UnsafeEnum::Variant6(0);
62-
//~^ ERROR destructors in statics are an unstable feature
6352

6453

6554
struct SafeStruct {
@@ -71,10 +60,8 @@ struct SafeStruct {
7160
// Struct fields are safe, hence this static should be safe
7261
static STATIC6: SafeStruct = SafeStruct{field1: SafeEnum::Variant1, field2: SafeEnum::Variant2(0)};
7362

74-
// field2 has an unsafe value, hence this should fail
7563
static STATIC7: SafeStruct = SafeStruct{field1: SafeEnum::Variant1,
7664
field2: SafeEnum::Variant3(WithDtor)};
77-
//~^ ERROR destructors in statics are an unstable feature
7865

7966
// Test variadic constructor for structs. The base struct should be examined
8067
// as well as every field present in the constructor.
@@ -86,8 +73,7 @@ static STATIC8: SafeStruct = SafeStruct{field1: SafeEnum::Variant1,
8673
// This example should fail because field1 in the base struct is not safe
8774
static STATIC9: SafeStruct = SafeStruct{field1: SafeEnum::Variant1,
8875
..SafeStruct{field1: SafeEnum::Variant3(WithDtor),
89-
//~^ ERROR destructors in statics are an unstable feature
90-
//~| ERROR statics are not allowed to have destructors
76+
//~^ ERROR destructors cannot be evaluated at compile-time
9177
field2: SafeEnum::Variant1}};
9278

9379
struct UnsafeStruct;
@@ -96,29 +82,19 @@ impl Drop for UnsafeStruct {
9682
fn drop(&mut self) {}
9783
}
9884

99-
// Types with destructors are not allowed for statics
10085
static STATIC10: UnsafeStruct = UnsafeStruct;
101-
//~^ ERROR destructors in statics are an unstable feature
10286

10387
struct MyOwned;
10488

10589
static STATIC11: Box<MyOwned> = box MyOwned;
10690
//~^ ERROR allocations are not allowed in statics
10791

108-
// The following examples test that mutable structs are just forbidden
109-
// to have types with destructors
110-
// These should fail
11192
static mut STATIC12: UnsafeStruct = UnsafeStruct;
112-
//~^ ERROR destructors in statics are an unstable feature
113-
//~^^ ERROR destructors in statics are an unstable feature
11493

11594
static mut STATIC13: SafeStruct = SafeStruct{field1: SafeEnum::Variant1,
116-
//~^ ERROR destructors in statics are an unstable feature
11795
field2: SafeEnum::Variant3(WithDtor)};
118-
//~^ ERROR: destructors in statics are an unstable feature
11996

12097
static mut STATIC14: SafeStruct = SafeStruct {
121-
//~^ ERROR destructors in statics are an unstable feature
12298
field1: SafeEnum::Variant1,
12399
field2: SafeEnum::Variant4("str".to_string())
124100
//~^ ERROR calls in statics are limited to constant functions
@@ -135,7 +111,6 @@ static STATIC16: (&'static Box<MyOwned>, &'static Box<MyOwned>) = (
135111
);
136112

137113
static mut STATIC17: SafeEnum = SafeEnum::Variant1;
138-
//~^ ERROR destructors in statics are an unstable feature
139114

140115
static STATIC19: Box<isize> =
141116
box 3;

src/test/compile-fail/issue-43733-2.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
// option. This file may not be copied, modified, or distributed
99
// except according to those terms.
1010

11-
#![feature(const_fn, drop_types_in_const)]
11+
#![feature(const_fn)]
1212
#![feature(cfg_target_thread_local, thread_local_internals)]
1313

1414
// On platforms *without* `#[thread_local]`, use

src/test/compile-fail/issue-43733.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
// option. This file may not be copied, modified, or distributed
99
// except according to those terms.
1010

11-
#![feature(const_fn, drop_types_in_const)]
11+
#![feature(const_fn)]
1212
#![feature(cfg_target_thread_local, thread_local_internals)]
1313

1414
type Foo = std::cell::RefCell<String>;

0 commit comments

Comments
 (0)