From 9c762b58ba9f46e806f7e07b80ef59b45de87471 Mon Sep 17 00:00:00 2001
From: Oli Scherer <git-spam-no-reply9815368754983@oli-obk.de>
Date: Mon, 18 Sep 2023 15:30:07 +0000
Subject: [PATCH] Prevent promotion of const fn calls in inline consts

---
 compiler/rustc_borrowck/src/universal_regions.rs   |  2 +-
 .../src/transform/check_consts/check.rs            |  2 +-
 .../src/transform/promote_consts.rs                |  2 +-
 compiler/rustc_errors/src/diagnostic_impls.rs      |  2 +-
 compiler/rustc_hir/src/hir.rs                      | 12 ++++++------
 compiler/rustc_hir_typeck/src/callee.rs            |  4 +++-
 compiler/rustc_hir_typeck/src/writeback.rs         |  2 +-
 compiler/rustc_middle/src/hir/map/mod.rs           |  7 ++++---
 compiler/rustc_mir_build/src/build/mod.rs          |  4 ++--
 compiler/rustc_mir_transform/src/lib.rs            |  2 +-
 compiler/rustc_passes/src/check_const.rs           |  4 ++--
 .../src/operators/arithmetic_side_effects.rs       |  2 +-
 .../src/operators/numeric_arithmetic.rs            |  2 +-
 tests/ui/inline-const/promotion.rs                 |  3 ++-
 tests/ui/inline-const/promotion.stderr             | 14 ++++++++++++++
 15 files changed, 41 insertions(+), 23 deletions(-)
 create mode 100644 tests/ui/inline-const/promotion.stderr

diff --git a/compiler/rustc_borrowck/src/universal_regions.rs b/compiler/rustc_borrowck/src/universal_regions.rs
index 3b5f1178db5..02b52784ede 100644
--- a/compiler/rustc_borrowck/src/universal_regions.rs
+++ b/compiler/rustc_borrowck/src/universal_regions.rs
@@ -580,7 +580,7 @@ impl<'cx, 'tcx> UniversalRegionsBuilder<'cx, 'tcx> {
                 }
             }
 
-            BodyOwnerKind::Const | BodyOwnerKind::Static(..) => {
+            BodyOwnerKind::Const { .. } | BodyOwnerKind::Static(..) => {
                 let identity_args = GenericArgs::identity_for_item(tcx, typeck_root_def_id);
                 if self.mir_def.to_def_id() == typeck_root_def_id {
                     let args =
diff --git a/compiler/rustc_const_eval/src/transform/check_consts/check.rs b/compiler/rustc_const_eval/src/transform/check_consts/check.rs
index f288ddc25d3..129e74425b6 100644
--- a/compiler/rustc_const_eval/src/transform/check_consts/check.rs
+++ b/compiler/rustc_const_eval/src/transform/check_consts/check.rs
@@ -167,7 +167,7 @@ impl<'mir, 'tcx> Qualifs<'mir, 'tcx> {
                 false
             }
 
-            hir::ConstContext::Const | hir::ConstContext::Static(_) => {
+            hir::ConstContext::Const { .. } | hir::ConstContext::Static(_) => {
                 let mut cursor = FlowSensitiveAnalysis::new(CustomEq, ccx)
                     .into_engine(ccx.tcx, &ccx.body)
                     .iterate_to_fixpoint()
diff --git a/compiler/rustc_const_eval/src/transform/promote_consts.rs b/compiler/rustc_const_eval/src/transform/promote_consts.rs
index d79c65f1d1f..81168c31802 100644
--- a/compiler/rustc_const_eval/src/transform/promote_consts.rs
+++ b/compiler/rustc_const_eval/src/transform/promote_consts.rs
@@ -644,7 +644,7 @@ impl<'tcx> Validator<'_, 'tcx> {
         // Everywhere else, we require `#[rustc_promotable]` on the callee.
         let promote_all_const_fn = matches!(
             self.const_kind,
-            Some(hir::ConstContext::Static(_) | hir::ConstContext::Const)
+            Some(hir::ConstContext::Static(_) | hir::ConstContext::Const { inline: false })
         );
         if !promote_all_const_fn {
             if let ty::FnDef(def_id, _) = *fn_ty.kind() {
diff --git a/compiler/rustc_errors/src/diagnostic_impls.rs b/compiler/rustc_errors/src/diagnostic_impls.rs
index a170e3a8943..4f77f09b26e 100644
--- a/compiler/rustc_errors/src/diagnostic_impls.rs
+++ b/compiler/rustc_errors/src/diagnostic_impls.rs
@@ -161,7 +161,7 @@ impl IntoDiagnosticArg for hir::ConstContext {
         DiagnosticArgValue::Str(Cow::Borrowed(match self {
             hir::ConstContext::ConstFn => "const_fn",
             hir::ConstContext::Static(_) => "static",
-            hir::ConstContext::Const => "const",
+            hir::ConstContext::Const { .. } => "const",
         }))
     }
 }
diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs
index cb78da42597..0c4a0e5d4a5 100644
--- a/compiler/rustc_hir/src/hir.rs
+++ b/compiler/rustc_hir/src/hir.rs
@@ -1581,8 +1581,8 @@ pub enum BodyOwnerKind {
     /// Closures
     Closure,
 
-    /// Constants and associated constants.
-    Const,
+    /// Constants and associated constants, also including inline constants.
+    Const { inline: bool },
 
     /// Initializer of a `static` item.
     Static(Mutability),
@@ -1592,7 +1592,7 @@ impl BodyOwnerKind {
     pub fn is_fn_or_closure(self) -> bool {
         match self {
             BodyOwnerKind::Fn | BodyOwnerKind::Closure => true,
-            BodyOwnerKind::Const | BodyOwnerKind::Static(_) => false,
+            BodyOwnerKind::Const { .. } | BodyOwnerKind::Static(_) => false,
         }
     }
 }
@@ -1615,7 +1615,7 @@ pub enum ConstContext {
     ///
     /// For the most part, other contexts are treated just like a regular `const`, so they are
     /// lumped into the same category.
-    Const,
+    Const { inline: bool },
 }
 
 impl ConstContext {
@@ -1624,7 +1624,7 @@ impl ConstContext {
     /// E.g. `const` or `static mut`.
     pub fn keyword_name(self) -> &'static str {
         match self {
-            Self::Const => "const",
+            Self::Const { .. } => "const",
             Self::Static(Mutability::Not) => "static",
             Self::Static(Mutability::Mut) => "static mut",
             Self::ConstFn => "const fn",
@@ -1637,7 +1637,7 @@ impl ConstContext {
 impl fmt::Display for ConstContext {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
         match *self {
-            Self::Const => write!(f, "constant"),
+            Self::Const { .. } => write!(f, "constant"),
             Self::Static(_) => write!(f, "static"),
             Self::ConstFn => write!(f, "constant function"),
         }
diff --git a/compiler/rustc_hir_typeck/src/callee.rs b/compiler/rustc_hir_typeck/src/callee.rs
index b39919ece71..f2c58ee2702 100644
--- a/compiler/rustc_hir_typeck/src/callee.rs
+++ b/compiler/rustc_hir_typeck/src/callee.rs
@@ -788,7 +788,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
 
         let effect = match const_context {
             _ if host_always_on => tcx.consts.true_,
-            Some(hir::ConstContext::Static(_) | hir::ConstContext::Const) => tcx.consts.false_,
+            Some(hir::ConstContext::Static(_) | hir::ConstContext::Const { .. }) => {
+                tcx.consts.false_
+            }
             Some(hir::ConstContext::ConstFn) => {
                 let args = ty::GenericArgs::identity_for_item(tcx, context);
                 args.host_effect_param().expect("ConstContext::Maybe must have host effect param")
diff --git a/compiler/rustc_hir_typeck/src/writeback.rs b/compiler/rustc_hir_typeck/src/writeback.rs
index 603681bbc99..2fe41c1197f 100644
--- a/compiler/rustc_hir_typeck/src/writeback.rs
+++ b/compiler/rustc_hir_typeck/src/writeback.rs
@@ -46,7 +46,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         }
         // Type only exists for constants and statics, not functions.
         match self.tcx.hir().body_owner_kind(item_def_id) {
-            hir::BodyOwnerKind::Const | hir::BodyOwnerKind::Static(_) => {
+            hir::BodyOwnerKind::Const { .. } | hir::BodyOwnerKind::Static(_) => {
                 let item_hir_id = self.tcx.hir().local_def_id_to_hir_id(item_def_id);
                 wbcx.visit_node_id(body.value.span, item_hir_id);
             }
diff --git a/compiler/rustc_middle/src/hir/map/mod.rs b/compiler/rustc_middle/src/hir/map/mod.rs
index f67f8015c04..3491c487f3e 100644
--- a/compiler/rustc_middle/src/hir/map/mod.rs
+++ b/compiler/rustc_middle/src/hir/map/mod.rs
@@ -442,9 +442,10 @@ impl<'hir> Map<'hir> {
     /// Panics if `LocalDefId` does not have an associated body.
     pub fn body_owner_kind(self, def_id: LocalDefId) -> BodyOwnerKind {
         match self.tcx.def_kind(def_id) {
-            DefKind::Const | DefKind::AssocConst | DefKind::InlineConst | DefKind::AnonConst => {
-                BodyOwnerKind::Const
+            DefKind::Const | DefKind::AssocConst | DefKind::AnonConst => {
+                BodyOwnerKind::Const { inline: false }
             }
+            DefKind::InlineConst => BodyOwnerKind::Const { inline: true },
             DefKind::Ctor(..) | DefKind::Fn | DefKind::AssocFn => BodyOwnerKind::Fn,
             DefKind::Closure | DefKind::Generator => BodyOwnerKind::Closure,
             DefKind::Static(mt) => BodyOwnerKind::Static(mt),
@@ -461,7 +462,7 @@ impl<'hir> Map<'hir> {
     /// just that it has to be checked as if it were.
     pub fn body_const_context(self, def_id: LocalDefId) -> Option<ConstContext> {
         let ccx = match self.body_owner_kind(def_id) {
-            BodyOwnerKind::Const => ConstContext::Const,
+            BodyOwnerKind::Const { inline } => ConstContext::Const { inline },
             BodyOwnerKind::Static(mt) => ConstContext::Static(mt),
 
             BodyOwnerKind::Fn if self.tcx.is_constructor(def_id.to_def_id()) => return None,
diff --git a/compiler/rustc_mir_build/src/build/mod.rs b/compiler/rustc_mir_build/src/build/mod.rs
index 7748ffab79c..bba47056457 100644
--- a/compiler/rustc_mir_build/src/build/mod.rs
+++ b/compiler/rustc_mir_build/src/build/mod.rs
@@ -633,7 +633,7 @@ fn construct_error(tcx: TyCtxt<'_>, def: LocalDefId, err: ErrorGuaranteed) -> Bo
                 _ => bug!("expected closure or generator, found {ty:?}"),
             }
         }
-        hir::BodyOwnerKind::Const => 0,
+        hir::BodyOwnerKind::Const { .. } => 0,
         hir::BodyOwnerKind::Static(_) => 0,
     };
     let mut cfg = CFG { basic_blocks: IndexVec::new() };
@@ -700,7 +700,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
         // Constants always need overflow checks.
         check_overflow |= matches!(
             tcx.hir().body_owner_kind(def),
-            hir::BodyOwnerKind::Const | hir::BodyOwnerKind::Static(_)
+            hir::BodyOwnerKind::Const { .. } | hir::BodyOwnerKind::Static(_)
         );
 
         let lint_level = LintLevel::Explicit(hir_id);
diff --git a/compiler/rustc_mir_transform/src/lib.rs b/compiler/rustc_mir_transform/src/lib.rs
index 70d4ea74d1a..c44192957b1 100644
--- a/compiler/rustc_mir_transform/src/lib.rs
+++ b/compiler/rustc_mir_transform/src/lib.rs
@@ -343,7 +343,7 @@ fn inner_mir_for_ctfe(tcx: TyCtxt<'_>, def: LocalDefId) -> Body<'_> {
     let body = match tcx.hir().body_const_context(def) {
         // consts and statics do not have `optimized_mir`, so we can steal the body instead of
         // cloning it.
-        Some(hir::ConstContext::Const | hir::ConstContext::Static(_)) => body.steal(),
+        Some(hir::ConstContext::Const { .. } | hir::ConstContext::Static(_)) => body.steal(),
         Some(hir::ConstContext::ConstFn) => body.borrow().clone(),
         None => bug!("`mir_for_ctfe` called on non-const {def:?}"),
     };
diff --git a/compiler/rustc_passes/src/check_const.rs b/compiler/rustc_passes/src/check_const.rs
index 8437e9a40e2..6d176af8098 100644
--- a/compiler/rustc_passes/src/check_const.rs
+++ b/compiler/rustc_passes/src/check_const.rs
@@ -193,12 +193,12 @@ impl<'tcx> Visitor<'tcx> for CheckConstVisitor<'tcx> {
     }
 
     fn visit_anon_const(&mut self, anon: &'tcx hir::AnonConst) {
-        let kind = Some(hir::ConstContext::Const);
+        let kind = Some(hir::ConstContext::Const { inline: false });
         self.recurse_into(kind, None, |this| intravisit::walk_anon_const(this, anon));
     }
 
     fn visit_inline_const(&mut self, block: &'tcx hir::ConstBlock) {
-        let kind = Some(hir::ConstContext::Const);
+        let kind = Some(hir::ConstContext::Const { inline: true });
         self.recurse_into(kind, None, |this| intravisit::walk_inline_const(this, block));
     }
 
diff --git a/src/tools/clippy/clippy_lints/src/operators/arithmetic_side_effects.rs b/src/tools/clippy/clippy_lints/src/operators/arithmetic_side_effects.rs
index 8072aded851..a10aa65e594 100644
--- a/src/tools/clippy/clippy_lints/src/operators/arithmetic_side_effects.rs
+++ b/src/tools/clippy/clippy_lints/src/operators/arithmetic_side_effects.rs
@@ -315,7 +315,7 @@ impl<'tcx> LateLintPass<'tcx> for ArithmeticSideEffects {
         let body_owner_def_id = cx.tcx.hir().body_owner_def_id(body.id());
 
         let body_owner_kind = cx.tcx.hir().body_owner_kind(body_owner_def_id);
-        if let hir::BodyOwnerKind::Const | hir::BodyOwnerKind::Static(_) = body_owner_kind {
+        if let hir::BodyOwnerKind::Const { .. } | hir::BodyOwnerKind::Static(_) = body_owner_kind {
             let body_span = cx.tcx.hir().span_with_body(body_owner);
             if let Some(span) = self.const_span && span.contains(body_span) {
                 return;
diff --git a/src/tools/clippy/clippy_lints/src/operators/numeric_arithmetic.rs b/src/tools/clippy/clippy_lints/src/operators/numeric_arithmetic.rs
index 102845ceed0..80389cbf84b 100644
--- a/src/tools/clippy/clippy_lints/src/operators/numeric_arithmetic.rs
+++ b/src/tools/clippy/clippy_lints/src/operators/numeric_arithmetic.rs
@@ -72,7 +72,7 @@ impl Context {
         let body_owner_def_id = cx.tcx.hir().body_owner_def_id(body.id());
 
         match cx.tcx.hir().body_owner_kind(body_owner_def_id) {
-            hir::BodyOwnerKind::Static(_) | hir::BodyOwnerKind::Const => {
+            hir::BodyOwnerKind::Static(_) | hir::BodyOwnerKind::Const { .. } => {
                 let body_span = cx.tcx.hir().span_with_body(body_owner);
 
                 if let Some(span) = self.const_span {
diff --git a/tests/ui/inline-const/promotion.rs b/tests/ui/inline-const/promotion.rs
index e211f46acf9..242959c6b51 100644
--- a/tests/ui/inline-const/promotion.rs
+++ b/tests/ui/inline-const/promotion.rs
@@ -1,8 +1,8 @@
 #![feature(inline_const)]
 #![allow(arithmetic_overflow, unconditional_panic)]
-// check-pass
 
 // The only way to have promoteds that fail is in `const fn` called from `const`/`static`.
+// Make sure that in a `const` block, we do not promote such calls.
 const fn div_by_zero() -> i32 {
     1 / 0
 }
@@ -15,6 +15,7 @@ fn main() {
     let v = const {
         if mk_false() {
             let _x: &'static i32 = &div_by_zero();
+            //~^ ERROR: temporary value dropped while borrowed
         }
         42
     };
diff --git a/tests/ui/inline-const/promotion.stderr b/tests/ui/inline-const/promotion.stderr
new file mode 100644
index 00000000000..795fc8f5921
--- /dev/null
+++ b/tests/ui/inline-const/promotion.stderr
@@ -0,0 +1,14 @@
+error[E0716]: temporary value dropped while borrowed
+  --> $DIR/promotion.rs:17:37
+   |
+LL |             let _x: &'static i32 = &div_by_zero();
+   |                     ------------    ^^^^^^^^^^^^^ creates a temporary value which is freed while still in use
+   |                     |
+   |                     type annotation requires that borrow lasts for `'static`
+LL |
+LL |         }
+   |         - temporary value is freed at the end of this statement
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0716`.