Skip to content

Commit a0724d7

Browse files
authored
Rollup merge of #89988 - tmiasko:unpromote-const-drop, r=oli-obk
Do not promote values with const drop that need to be dropped Changes from #88558 allowed using `~const Drop` in constants by introducing a new `NeedsNonConstDrop` qualif. The new qualif was also used for promotion purposes, and allowed promotion to happen for values that needs to be dropped but which do have a const drop impl. Since for promoted the drop implementation is never executed, this lead to observable change in behaviour. For example: ```rust struct Panic(); impl const Drop for Panic { fn drop(&mut self) { panic!(); } } fn main() { let _ = &Panic(); } ``` Restore the use of `NeedsDrop` qualif during promotion to avoid the issue.
2 parents 8c8835d + 915a581 commit a0724d7

File tree

7 files changed

+107
-15
lines changed

7 files changed

+107
-15
lines changed

compiler/rustc_const_eval/src/transform/check_consts/check.rs

Lines changed: 37 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ use std::mem;
2222
use std::ops::Deref;
2323

2424
use super::ops::{self, NonConstOp, Status};
25-
use super::qualifs::{self, CustomEq, HasMutInterior, NeedsNonConstDrop};
25+
use super::qualifs::{self, CustomEq, HasMutInterior, NeedsDrop, NeedsNonConstDrop};
2626
use super::resolver::FlowSensitiveAnalysis;
2727
use super::{is_lang_panic_fn, is_lang_special_const_fn, ConstCx, Qualif};
2828
use crate::const_eval::is_unstable_const_fn;
@@ -39,7 +39,8 @@ type QualifResults<'mir, 'tcx, Q> =
3939
#[derive(Default)]
4040
pub struct Qualifs<'mir, 'tcx> {
4141
has_mut_interior: Option<QualifResults<'mir, 'tcx, HasMutInterior>>,
42-
needs_drop: Option<QualifResults<'mir, 'tcx, NeedsNonConstDrop>>,
42+
needs_drop: Option<QualifResults<'mir, 'tcx, NeedsDrop>>,
43+
needs_non_const_drop: Option<QualifResults<'mir, 'tcx, NeedsNonConstDrop>>,
4344
indirectly_mutable: Option<IndirectlyMutableResults<'mir, 'tcx>>,
4445
}
4546

@@ -80,14 +81,14 @@ impl Qualifs<'mir, 'tcx> {
8081
location: Location,
8182
) -> bool {
8283
let ty = ccx.body.local_decls[local].ty;
83-
if !NeedsNonConstDrop::in_any_value_of_ty(ccx, ty) {
84+
if !NeedsDrop::in_any_value_of_ty(ccx, ty) {
8485
return false;
8586
}
8687

8788
let needs_drop = self.needs_drop.get_or_insert_with(|| {
8889
let ConstCx { tcx, body, .. } = *ccx;
8990

90-
FlowSensitiveAnalysis::new(NeedsNonConstDrop, ccx)
91+
FlowSensitiveAnalysis::new(NeedsDrop, ccx)
9192
.into_engine(tcx, &body)
9293
.iterate_to_fixpoint()
9394
.into_results_cursor(&body)
@@ -97,6 +98,33 @@ impl Qualifs<'mir, 'tcx> {
9798
needs_drop.get().contains(local) || self.indirectly_mutable(ccx, local, location)
9899
}
99100

101+
/// Returns `true` if `local` is `NeedsNonConstDrop` at the given `Location`.
102+
///
103+
/// Only updates the cursor if absolutely necessary
104+
pub fn needs_non_const_drop(
105+
&mut self,
106+
ccx: &'mir ConstCx<'mir, 'tcx>,
107+
local: Local,
108+
location: Location,
109+
) -> bool {
110+
let ty = ccx.body.local_decls[local].ty;
111+
if !NeedsNonConstDrop::in_any_value_of_ty(ccx, ty) {
112+
return false;
113+
}
114+
115+
let needs_non_const_drop = self.needs_non_const_drop.get_or_insert_with(|| {
116+
let ConstCx { tcx, body, .. } = *ccx;
117+
118+
FlowSensitiveAnalysis::new(NeedsNonConstDrop, ccx)
119+
.into_engine(tcx, &body)
120+
.iterate_to_fixpoint()
121+
.into_results_cursor(&body)
122+
});
123+
124+
needs_non_const_drop.seek_before_primary_effect(location);
125+
needs_non_const_drop.get().contains(local) || self.indirectly_mutable(ccx, local, location)
126+
}
127+
100128
/// Returns `true` if `local` is `HasMutInterior` at the given `Location`.
101129
///
102130
/// Only updates the cursor if absolutely necessary.
@@ -173,6 +201,7 @@ impl Qualifs<'mir, 'tcx> {
173201

174202
ConstQualifs {
175203
needs_drop: self.needs_drop(ccx, RETURN_PLACE, return_loc),
204+
needs_non_const_drop: self.needs_non_const_drop(ccx, RETURN_PLACE, return_loc),
176205
has_mut_interior: self.has_mut_interior(ccx, RETURN_PLACE, return_loc),
177206
custom_eq,
178207
error_occured,
@@ -999,7 +1028,7 @@ impl Visitor<'tcx> for Checker<'mir, 'tcx> {
9991028
}
10001029

10011030
// Forbid all `Drop` terminators unless the place being dropped is a local with no
1002-
// projections that cannot be `NeedsDrop`.
1031+
// projections that cannot be `NeedsNonConstDrop`.
10031032
TerminatorKind::Drop { place: dropped_place, .. }
10041033
| TerminatorKind::DropAndReplace { place: dropped_place, .. } => {
10051034
// If we are checking live drops after drop-elaboration, don't emit duplicate
@@ -1019,15 +1048,15 @@ impl Visitor<'tcx> for Checker<'mir, 'tcx> {
10191048
return;
10201049
}
10211050

1022-
let needs_drop = if let Some(local) = dropped_place.as_local() {
1051+
let needs_non_const_drop = if let Some(local) = dropped_place.as_local() {
10231052
// Use the span where the local was declared as the span of the drop error.
10241053
err_span = self.body.local_decls[local].source_info.span;
1025-
self.qualifs.needs_drop(self.ccx, local, location)
1054+
self.qualifs.needs_non_const_drop(self.ccx, local, location)
10261055
} else {
10271056
true
10281057
};
10291058

1030-
if needs_drop {
1059+
if needs_non_const_drop {
10311060
self.check_op_spanned(
10321061
ops::LiveDrop { dropped_at: Some(terminator.source_info.span) },
10331062
err_span,

compiler/rustc_const_eval/src/transform/check_consts/post_drop_elaboration.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -97,7 +97,7 @@ impl Visitor<'tcx> for CheckLiveDrops<'mir, 'tcx> {
9797
// `src/test/ui/consts/control-flow/drop-pass.rs`; e.g., when an `Option<Vec<T>>` is
9898
// initialized with `None` and never changed, it still emits drop glue.
9999
// Hence we additionally check the qualifs here to allow more code to pass.
100-
if self.qualifs.needs_drop(self.ccx, dropped_place.local, location) {
100+
if self.qualifs.needs_non_const_drop(self.ccx, dropped_place.local, location) {
101101
// Use the span where the dropped local was declared for the error.
102102
let span = self.body.local_decls[dropped_place.local].source_info.span;
103103
self.check_live_drop(span);

compiler/rustc_const_eval/src/transform/check_consts/qualifs.rs

Lines changed: 28 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,8 @@ pub fn in_any_value_of_ty(
2121
) -> ConstQualifs {
2222
ConstQualifs {
2323
has_mut_interior: HasMutInterior::in_any_value_of_ty(cx, ty),
24-
needs_drop: NeedsNonConstDrop::in_any_value_of_ty(cx, ty),
24+
needs_drop: NeedsDrop::in_any_value_of_ty(cx, ty),
25+
needs_non_const_drop: NeedsNonConstDrop::in_any_value_of_ty(cx, ty),
2526
custom_eq: CustomEq::in_any_value_of_ty(cx, ty),
2627
error_occured,
2728
}
@@ -98,17 +99,39 @@ impl Qualif for HasMutInterior {
9899
}
99100

100101
/// Constant containing an ADT that implements `Drop`.
101-
/// This must be ruled out (a) because we cannot run `Drop` during compile-time
102-
/// as that might not be a `const fn`, and (b) because implicit promotion would
103-
/// remove side-effects that occur as part of dropping that value.
102+
/// This must be ruled out because implicit promotion would remove side-effects
103+
/// that occur as part of dropping that value. N.B., the implicit promotion has
104+
/// to reject const Drop implementations because even if side-effects are ruled
105+
/// out through other means, the execution of the drop could diverge.
106+
pub struct NeedsDrop;
107+
108+
impl Qualif for NeedsDrop {
109+
const ANALYSIS_NAME: &'static str = "flow_needs_drop";
110+
const IS_CLEARED_ON_MOVE: bool = true;
111+
112+
fn in_qualifs(qualifs: &ConstQualifs) -> bool {
113+
qualifs.needs_drop
114+
}
115+
116+
fn in_any_value_of_ty(cx: &ConstCx<'_, 'tcx>, ty: Ty<'tcx>) -> bool {
117+
ty.needs_drop(cx.tcx, cx.param_env)
118+
}
119+
120+
fn in_adt_inherently(cx: &ConstCx<'_, 'tcx>, adt: &'tcx AdtDef, _: SubstsRef<'tcx>) -> bool {
121+
adt.has_dtor(cx.tcx)
122+
}
123+
}
124+
125+
/// Constant containing an ADT that implements non-const `Drop`.
126+
/// This must be ruled out because we cannot run `Drop` during compile-time.
104127
pub struct NeedsNonConstDrop;
105128

106129
impl Qualif for NeedsNonConstDrop {
107130
const ANALYSIS_NAME: &'static str = "flow_needs_nonconst_drop";
108131
const IS_CLEARED_ON_MOVE: bool = true;
109132

110133
fn in_qualifs(qualifs: &ConstQualifs) -> bool {
111-
qualifs.needs_drop
134+
qualifs.needs_non_const_drop
112135
}
113136

114137
fn in_any_value_of_ty(cx: &ConstCx<'_, 'tcx>, mut ty: Ty<'tcx>) -> bool {

compiler/rustc_const_eval/src/transform/promote_consts.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -230,7 +230,7 @@ impl<'tcx> Validator<'_, 'tcx> {
230230

231231
// We cannot promote things that need dropping, since the promoted value
232232
// would not get dropped.
233-
if self.qualif_local::<qualifs::NeedsNonConstDrop>(place.local) {
233+
if self.qualif_local::<qualifs::NeedsDrop>(place.local) {
234234
return Err(Unpromotable);
235235
}
236236

compiler/rustc_middle/src/mir/query.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -225,6 +225,7 @@ pub struct BorrowCheckResult<'tcx> {
225225
pub struct ConstQualifs {
226226
pub has_mut_interior: bool,
227227
pub needs_drop: bool,
228+
pub needs_non_const_drop: bool,
228229
pub custom_eq: bool,
229230
pub error_occured: Option<ErrorReported>,
230231
}
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
#![feature(const_trait_impl)]
2+
#![feature(const_mut_refs)]
3+
4+
struct A();
5+
6+
impl const Drop for A {
7+
fn drop(&mut self) {}
8+
}
9+
10+
const C: A = A();
11+
12+
fn main() {
13+
let _: &'static A = &A(); //~ ERROR temporary value dropped while borrowed
14+
let _: &'static [A] = &[C]; //~ ERROR temporary value dropped while borrowed
15+
}
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
error[E0716]: temporary value dropped while borrowed
2+
--> $DIR/promoted-const-drop.rs:13:26
3+
|
4+
LL | let _: &'static A = &A();
5+
| ---------- ^^^ creates a temporary which is freed while still in use
6+
| |
7+
| type annotation requires that borrow lasts for `'static`
8+
LL | let _: &'static [A] = &[C];
9+
LL | }
10+
| - temporary value is freed at the end of this statement
11+
12+
error[E0716]: temporary value dropped while borrowed
13+
--> $DIR/promoted-const-drop.rs:14:28
14+
|
15+
LL | let _: &'static [A] = &[C];
16+
| ------------ ^^^ creates a temporary which is freed while still in use
17+
| |
18+
| type annotation requires that borrow lasts for `'static`
19+
LL | }
20+
| - temporary value is freed at the end of this statement
21+
22+
error: aborting due to 2 previous errors
23+
24+
For more information about this error, try `rustc --explain E0716`.

0 commit comments

Comments
 (0)