From 7581bae99615f0b7b3dd973a59448659d2946656 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Mi=C4=85sko?= Date: Tue, 19 Oct 2021 00:00:00 +0000 Subject: [PATCH 1/2] Fix const qualification when executed after promotion The const qualification was so far performed before the promotion and the implementation assumed that it will never encounter a promoted. With `const_precise_live_drops` feature, checking for live drops is delayed until after drop elaboration, which in turn runs after promotion. so the assumption is no longer true. When evaluating `NeedsNonConstDrop` it is now possible to encounter promoteds. Use type base qualification for the promoted. It is a sound approximation in general, and in the specific case of promoteds and `NeedsNonConstDrop` it is precise. --- .../src/transform/check_consts/qualifs.rs | 5 +++-- src/test/ui/consts/precise-drop-with-promoted.rs | 9 +++++++++ 2 files changed, 12 insertions(+), 2 deletions(-) create mode 100644 src/test/ui/consts/precise-drop-with-promoted.rs diff --git a/compiler/rustc_const_eval/src/transform/check_consts/qualifs.rs b/compiler/rustc_const_eval/src/transform/check_consts/qualifs.rs index 5418f6fc007ca..0a57d9adc46a9 100644 --- a/compiler/rustc_const_eval/src/transform/check_consts/qualifs.rs +++ b/compiler/rustc_const_eval/src/transform/check_consts/qualifs.rs @@ -309,8 +309,9 @@ where // Check the qualifs of the value of `const` items. if let Some(ct) = constant.literal.const_for_ty() { - if let ty::ConstKind::Unevaluated(ty::Unevaluated { def, substs_: _, promoted }) = ct.val { - assert!(promoted.is_none()); + if let ty::ConstKind::Unevaluated(ty::Unevaluated { def, substs_: _, promoted: None }) = + ct.val + { // Don't peek inside trait associated constants. if cx.tcx.trait_of_item(def.did).is_none() { let qualifs = if let Some((did, param_did)) = def.as_const_arg() { diff --git a/src/test/ui/consts/precise-drop-with-promoted.rs b/src/test/ui/consts/precise-drop-with-promoted.rs new file mode 100644 index 0000000000000..6f2317a5a27a8 --- /dev/null +++ b/src/test/ui/consts/precise-drop-with-promoted.rs @@ -0,0 +1,9 @@ +// Regression test for issue #89938. +// check-pass +// compile-flags: --crate-type=lib +#![feature(const_precise_live_drops)] + +pub const fn f() { + let _: Option = None; + let _: &'static Option = &None; +} From 74c6636d27fe95e79d130f7420302d5db2559c3b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Mi=C4=85sko?= Date: Thu, 21 Oct 2021 00:00:00 +0000 Subject: [PATCH 2/2] Verify that only NeedsNonConstDrop expects promoteds --- .../src/transform/check_consts/qualifs.rs | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/compiler/rustc_const_eval/src/transform/check_consts/qualifs.rs b/compiler/rustc_const_eval/src/transform/check_consts/qualifs.rs index 0a57d9adc46a9..aaeb1eeb04397 100644 --- a/compiler/rustc_const_eval/src/transform/check_consts/qualifs.rs +++ b/compiler/rustc_const_eval/src/transform/check_consts/qualifs.rs @@ -46,6 +46,9 @@ pub trait Qualif { /// Whether this `Qualif` is cleared when a local is moved from. const IS_CLEARED_ON_MOVE: bool = false; + /// Whether this `Qualif` might be evaluated after the promotion and can encounter a promoted. + const ALLOW_PROMOTED: bool = false; + /// Extracts the field of `ConstQualifs` that corresponds to this `Qualif`. fn in_qualifs(qualifs: &ConstQualifs) -> bool; @@ -129,6 +132,7 @@ pub struct NeedsNonConstDrop; impl Qualif for NeedsNonConstDrop { const ANALYSIS_NAME: &'static str = "flow_needs_nonconst_drop"; const IS_CLEARED_ON_MOVE: bool = true; + const ALLOW_PROMOTED: bool = true; fn in_qualifs(qualifs: &ConstQualifs) -> bool { qualifs.needs_non_const_drop @@ -309,11 +313,13 @@ where // Check the qualifs of the value of `const` items. if let Some(ct) = constant.literal.const_for_ty() { - if let ty::ConstKind::Unevaluated(ty::Unevaluated { def, substs_: _, promoted: None }) = - ct.val - { + if let ty::ConstKind::Unevaluated(ty::Unevaluated { def, substs_: _, promoted }) = ct.val { + // Use qualifs of the type for the promoted. Promoteds in MIR body should be possible + // only for `NeedsNonConstDrop` with precise drop checking. This is the only const + // check performed after the promotion. Verify that with an assertion. + assert!(promoted.is_none() || Q::ALLOW_PROMOTED); // Don't peek inside trait associated constants. - if cx.tcx.trait_of_item(def.did).is_none() { + if promoted.is_none() && cx.tcx.trait_of_item(def.did).is_none() { let qualifs = if let Some((did, param_did)) = def.as_const_arg() { cx.tcx.at(constant.span).mir_const_qualif_const_arg((did, param_did)) } else {