about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--src/librustc_mir/transform/check_consts/mod.rs68
-rw-r--r--src/librustc_mir/transform/check_consts/ops.rs7
-rw-r--r--src/librustc_mir/transform/check_consts/validation.rs25
-rw-r--r--src/librustc_mir/transform/mod.rs2
-rw-r--r--src/librustc_mir/transform/promote_consts.rs11
-rw-r--r--src/librustc_passes/check_const.rs55
6 files changed, 34 insertions, 134 deletions
diff --git a/src/librustc_mir/transform/check_consts/mod.rs b/src/librustc_mir/transform/check_consts/mod.rs
index 46a46aa5ae9..7c439f80ef6 100644
--- a/src/librustc_mir/transform/check_consts/mod.rs
+++ b/src/librustc_mir/transform/check_consts/mod.rs
@@ -9,8 +9,6 @@ use rustc_hir::def_id::{DefId, LocalDefId};
 use rustc_middle::mir;
 use rustc_middle::ty::{self, TyCtxt};
 
-use std::fmt;
-
 pub use self::qualifs::Qualif;
 
 mod ops;
@@ -25,7 +23,7 @@ pub struct ConstCx<'mir, 'tcx> {
     pub tcx: TyCtxt<'tcx>,
     pub def_id: DefId,
     pub param_env: ty::ParamEnv<'tcx>,
-    pub const_kind: Option<ConstKind>,
+    pub const_kind: Option<hir::ConstContext>,
 }
 
 impl ConstCx<'mir, 'tcx> {
@@ -40,78 +38,18 @@ impl ConstCx<'mir, 'tcx> {
         body: &'mir mir::Body<'tcx>,
         param_env: ty::ParamEnv<'tcx>,
     ) -> Self {
-        let const_kind = ConstKind::for_item(tcx, def_id);
-
+        let const_kind = tcx.hir().body_const_context(def_id);
         ConstCx { body, tcx, def_id: def_id.to_def_id(), param_env, const_kind }
     }
 
     /// Returns the kind of const context this `Item` represents (`const`, `static`, etc.).
     ///
     /// Panics if this `Item` is not const.
-    pub fn const_kind(&self) -> ConstKind {
+    pub fn const_kind(&self) -> hir::ConstContext {
         self.const_kind.expect("`const_kind` must not be called on a non-const fn")
     }
 }
 
-/// The kinds of items which require compile-time evaluation.
-#[derive(Copy, Clone, Debug, PartialEq, Eq)]
-pub enum ConstKind {
-    /// A `static` item.
-    Static,
-    /// A `static mut` item.
-    StaticMut,
-    /// A `const fn` item.
-    ConstFn,
-    /// A `const` item or an anonymous constant (e.g. in array lengths).
-    Const,
-}
-
-impl ConstKind {
-    /// Returns the validation mode for the item with the given `DefId`, or `None` if this item
-    /// does not require validation (e.g. a non-const `fn`).
-    pub fn for_item(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> Option<Self> {
-        use hir::BodyOwnerKind as HirKind;
-
-        let hir_id = tcx.hir().as_local_hir_id(def_id);
-
-        let mode = match tcx.hir().body_owner_kind(hir_id) {
-            HirKind::Closure => return None,
-
-            // Note: this is deliberately checking for `is_const_fn_raw`, as the `is_const_fn`
-            // checks take into account the `rustc_const_unstable` attribute combined with enabled
-            // feature gates. Otherwise, const qualification would _not check_ whether this
-            // function body follows the `const fn` rules, as an unstable `const fn` would
-            // be considered "not const". More details are available in issue #67053.
-            HirKind::Fn if tcx.is_const_fn_raw(def_id) => ConstKind::ConstFn,
-            HirKind::Fn => return None,
-
-            HirKind::Const => ConstKind::Const,
-
-            HirKind::Static(hir::Mutability::Not) => ConstKind::Static,
-            HirKind::Static(hir::Mutability::Mut) => ConstKind::StaticMut,
-        };
-
-        Some(mode)
-    }
-
-    pub fn is_static(self) -> bool {
-        match self {
-            ConstKind::Static | ConstKind::StaticMut => true,
-            ConstKind::ConstFn | ConstKind::Const => false,
-        }
-    }
-}
-
-impl fmt::Display for ConstKind {
-    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        match *self {
-            ConstKind::Const => write!(f, "constant"),
-            ConstKind::Static | ConstKind::StaticMut => write!(f, "static"),
-            ConstKind::ConstFn => write!(f, "constant function"),
-        }
-    }
-}
-
 /// Returns `true` if this `DefId` points to one of the official `panic` lang items.
 pub fn is_lang_panic_fn(tcx: TyCtxt<'tcx>, def_id: DefId) -> bool {
     Some(def_id) == tcx.lang_items().panic_fn() || Some(def_id) == tcx.lang_items().begin_panic_fn()
diff --git a/src/librustc_mir/transform/check_consts/ops.rs b/src/librustc_mir/transform/check_consts/ops.rs
index fe20ceb47ee..20277b09e32 100644
--- a/src/librustc_mir/transform/check_consts/ops.rs
+++ b/src/librustc_mir/transform/check_consts/ops.rs
@@ -1,13 +1,14 @@
 //! Concrete error types for all operations which may be invalid in a certain const context.
 
 use rustc_errors::struct_span_err;
+use rustc_hir as hir;
 use rustc_hir::def_id::DefId;
 use rustc_session::config::nightly_options;
 use rustc_session::parse::feature_err;
 use rustc_span::symbol::sym;
 use rustc_span::{Span, Symbol};
 
-use super::{ConstCx, ConstKind};
+use super::ConstCx;
 
 /// An operation that is not *always* allowed in a const context.
 pub trait NonConstOp: std::fmt::Debug {
@@ -323,7 +324,7 @@ impl NonConstOp for RawPtrToIntCast {
 pub struct StaticAccess;
 impl NonConstOp for StaticAccess {
     fn is_allowed_in_item(&self, ccx: &ConstCx<'_, '_>) -> bool {
-        ccx.const_kind().is_static()
+        matches!(ccx.const_kind(), hir::ConstContext::Static(_))
     }
 
     fn emit_error(&self, ccx: &ConstCx<'_, '_>, span: Span) {
@@ -371,7 +372,7 @@ pub struct UnionAccess;
 impl NonConstOp for UnionAccess {
     fn is_allowed_in_item(&self, ccx: &ConstCx<'_, '_>) -> bool {
         // Union accesses are stable in all contexts except `const fn`.
-        ccx.const_kind() != ConstKind::ConstFn
+        ccx.const_kind() != hir::ConstContext::ConstFn
             || ccx.tcx.features().enabled(Self::feature_gate().unwrap())
     }
 
diff --git a/src/librustc_mir/transform/check_consts/validation.rs b/src/librustc_mir/transform/check_consts/validation.rs
index 3fd9131d5db..af056bc0aaa 100644
--- a/src/librustc_mir/transform/check_consts/validation.rs
+++ b/src/librustc_mir/transform/check_consts/validation.rs
@@ -1,7 +1,7 @@
 //! The `Visitor` responsible for actually checking a `mir::Body` for invalid operations.
 
 use rustc_errors::struct_span_err;
-use rustc_hir::lang_items;
+use rustc_hir::{self as hir, lang_items};
 use rustc_hir::{def_id::DefId, HirId};
 use rustc_infer::infer::TyCtxtInferExt;
 use rustc_middle::mir::visit::{MutatingUseContext, NonMutatingUseContext, PlaceContext, Visitor};
@@ -18,7 +18,7 @@ use std::ops::Deref;
 use super::ops::{self, NonConstOp};
 use super::qualifs::{self, CustomEq, HasMutInterior, NeedsDrop};
 use super::resolver::FlowSensitiveAnalysis;
-use super::{is_lang_panic_fn, ConstCx, ConstKind, Qualif};
+use super::{is_lang_panic_fn, ConstCx, Qualif};
 use crate::const_eval::{is_const_fn, is_unstable_const_fn};
 use crate::dataflow::MaybeMutBorrowedLocals;
 use crate::dataflow::{self, Analysis};
@@ -145,17 +145,13 @@ impl Qualifs<'mir, 'tcx> {
             // We don't care whether a `const fn` returns a value that is not structurally
             // matchable. Functions calls are opaque and always use type-based qualification, so
             // this value should never be used.
-            ConstKind::ConstFn => true,
+            hir::ConstContext::ConstFn => true,
 
             // If we know that all values of the return type are structurally matchable, there's no
             // need to run dataflow.
-            ConstKind::Const | ConstKind::Static | ConstKind::StaticMut
-                if !CustomEq::in_any_value_of_ty(ccx, ccx.body.return_ty()) =>
-            {
-                false
-            }
+            _ if !CustomEq::in_any_value_of_ty(ccx, ccx.body.return_ty()) => false,
 
-            ConstKind::Const | ConstKind::Static | ConstKind::StaticMut => {
+            hir::ConstContext::Const | hir::ConstContext::Static(_) => {
                 let mut cursor = FlowSensitiveAnalysis::new(CustomEq, ccx)
                     .into_engine(ccx.tcx, &ccx.body, ccx.def_id)
                     .iterate_to_fixpoint()
@@ -198,7 +194,7 @@ impl Validator<'mir, 'tcx> {
     pub fn check_body(&mut self) {
         let ConstCx { tcx, body, def_id, const_kind, .. } = *self.ccx;
 
-        let use_min_const_fn_checks = (const_kind == Some(ConstKind::ConstFn)
+        let use_min_const_fn_checks = (const_kind == Some(hir::ConstContext::ConstFn)
             && crate::const_eval::is_min_const_fn(tcx, def_id))
             && !tcx.sess.opts.debugging_opts.unleash_the_miri_inside_of_you;
 
@@ -222,8 +218,9 @@ impl Validator<'mir, 'tcx> {
         self.visit_body(&body);
 
         // Ensure that the end result is `Sync` in a non-thread local `static`.
-        let should_check_for_sync =
-            const_kind == Some(ConstKind::Static) && !tcx.is_thread_local_static(def_id);
+        let should_check_for_sync = const_kind
+            == Some(hir::ConstContext::Static(hir::Mutability::Not))
+            && !tcx.is_thread_local_static(def_id);
 
         if should_check_for_sync {
             let hir_id = tcx.hir().as_local_hir_id(def_id.expect_local());
@@ -351,7 +348,9 @@ impl Visitor<'tcx> for Validator<'mir, 'tcx> {
                 let ty = place.ty(self.body, self.tcx).ty;
                 let is_allowed = match ty.kind {
                     // Inside a `static mut`, `&mut [...]` is allowed.
-                    ty::Array(..) | ty::Slice(_) if self.const_kind() == ConstKind::StaticMut => {
+                    ty::Array(..) | ty::Slice(_)
+                        if self.const_kind() == hir::ConstContext::Static(hir::Mutability::Mut) =>
+                    {
                         true
                     }
 
diff --git a/src/librustc_mir/transform/mod.rs b/src/librustc_mir/transform/mod.rs
index 1d982d18eeb..02356a43699 100644
--- a/src/librustc_mir/transform/mod.rs
+++ b/src/librustc_mir/transform/mod.rs
@@ -182,7 +182,7 @@ pub fn run_passes(
 }
 
 fn mir_const_qualif(tcx: TyCtxt<'_>, def_id: DefId) -> ConstQualifs {
-    let const_kind = check_consts::ConstKind::for_item(tcx, def_id.expect_local());
+    let const_kind = tcx.hir().body_const_context(def_id.expect_local());
 
     // No need to const-check a non-const `fn`.
     if const_kind.is_none() {
diff --git a/src/librustc_mir/transform/promote_consts.rs b/src/librustc_mir/transform/promote_consts.rs
index ad98920eb63..467e4188814 100644
--- a/src/librustc_mir/transform/promote_consts.rs
+++ b/src/librustc_mir/transform/promote_consts.rs
@@ -13,6 +13,7 @@
 //! move analysis runs after promotion on broken MIR.
 
 use rustc_ast::ast::LitKind;
+use rustc_hir as hir;
 use rustc_hir::def_id::DefId;
 use rustc_middle::mir::traversal::ReversePostorder;
 use rustc_middle::mir::visit::{MutVisitor, MutatingUseContext, PlaceContext, Visitor};
@@ -30,7 +31,7 @@ use std::cell::Cell;
 use std::{cmp, iter, mem};
 
 use crate::const_eval::{is_const_fn, is_unstable_const_fn};
-use crate::transform::check_consts::{is_lang_panic_fn, qualifs, ConstCx, ConstKind};
+use crate::transform::check_consts::{is_lang_panic_fn, qualifs, ConstCx};
 use crate::transform::{MirPass, MirSource};
 
 /// A `MirPass` for promotion.
@@ -352,7 +353,9 @@ impl<'tcx> Validator<'_, 'tcx> {
                             // In theory, any zero-sized value could be borrowed
                             // mutably without consequences. However, only &mut []
                             // is allowed right now, and only in functions.
-                            if self.const_kind == Some(ConstKind::StaticMut) {
+                            if self.const_kind
+                                == Some(hir::ConstContext::Static(hir::Mutability::Mut))
+                            {
                                 // Inside a `static mut`, &mut [...] is also allowed.
                                 match ty.kind {
                                     ty::Array(..) | ty::Slice(_) => {}
@@ -517,7 +520,7 @@ impl<'tcx> Validator<'_, 'tcx> {
                 if let Some(def_id) = c.check_static_ptr(self.tcx) {
                     // Only allow statics (not consts) to refer to other statics.
                     // FIXME(eddyb) does this matter at all for promotion?
-                    let is_static = self.const_kind.map_or(false, |k| k.is_static());
+                    let is_static = matches!(self.const_kind, Some(hir::ConstContext::Static(_)));
                     if !is_static {
                         return Err(Unpromotable);
                     }
@@ -607,7 +610,7 @@ impl<'tcx> Validator<'_, 'tcx> {
                     // In theory, any zero-sized value could be borrowed
                     // mutably without consequences. However, only &mut []
                     // is allowed right now, and only in functions.
-                    if self.const_kind == Some(ConstKind::StaticMut) {
+                    if self.const_kind == Some(hir::ConstContext::Static(hir::Mutability::Mut)) {
                         // Inside a `static mut`, &mut [...] is also allowed.
                         match ty.kind {
                             ty::Array(..) | ty::Slice(_) => {}
diff --git a/src/librustc_passes/check_const.rs b/src/librustc_passes/check_const.rs
index c42f2fc264a..94f9c619a3a 100644
--- a/src/librustc_passes/check_const.rs
+++ b/src/librustc_passes/check_const.rs
@@ -7,7 +7,6 @@
 //! errors. We still look for those primitives in the MIR const-checker to ensure nothing slips
 //! through, but errors for structured control flow in a `const` should be emitted here.
 
-use rustc_ast::ast::Mutability;
 use rustc_errors::struct_span_err;
 use rustc_hir as hir;
 use rustc_hir::def_id::DefId;
@@ -19,8 +18,6 @@ use rustc_session::config::nightly_options;
 use rustc_session::parse::feature_err;
 use rustc_span::{sym, Span, Symbol};
 
-use std::fmt;
-
 /// An expression that is not *always* legal in a const context.
 #[derive(Clone, Copy)]
 enum NonConstExpr {
@@ -65,46 +62,6 @@ impl NonConstExpr {
     }
 }
 
-#[derive(Copy, Clone)]
-enum ConstKind {
-    Static,
-    StaticMut,
-    ConstFn,
-    Const,
-    AnonConst,
-}
-
-impl ConstKind {
-    fn for_body(body: &hir::Body<'_>, tcx: TyCtxt<'_>) -> Option<Self> {
-        let owner = tcx.hir().body_owner(body.id());
-        let const_kind = match tcx.hir().body_owner_kind(owner) {
-            hir::BodyOwnerKind::Const => Self::Const,
-            hir::BodyOwnerKind::Static(Mutability::Mut) => Self::StaticMut,
-            hir::BodyOwnerKind::Static(Mutability::Not) => Self::Static,
-
-            hir::BodyOwnerKind::Fn if tcx.is_const_fn_raw(tcx.hir().local_def_id(owner)) => {
-                Self::ConstFn
-            }
-            hir::BodyOwnerKind::Fn | hir::BodyOwnerKind::Closure => return None,
-        };
-
-        Some(const_kind)
-    }
-}
-
-impl fmt::Display for ConstKind {
-    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        let s = match self {
-            Self::Static => "static",
-            Self::StaticMut => "static mut",
-            Self::Const | Self::AnonConst => "const",
-            Self::ConstFn => "const fn",
-        };
-
-        write!(f, "{}", s)
-    }
-}
-
 fn check_mod_const_bodies(tcx: TyCtxt<'_>, module_def_id: DefId) {
     let mut vis = CheckConstVisitor::new(tcx);
     tcx.hir().visit_item_likes_in_module(module_def_id, &mut vis.as_deep_visitor());
@@ -117,7 +74,7 @@ pub(crate) fn provide(providers: &mut Providers<'_>) {
 #[derive(Copy, Clone)]
 struct CheckConstVisitor<'tcx> {
     tcx: TyCtxt<'tcx>,
-    const_kind: Option<ConstKind>,
+    const_kind: Option<hir::ConstContext>,
 }
 
 impl<'tcx> CheckConstVisitor<'tcx> {
@@ -147,7 +104,8 @@ impl<'tcx> CheckConstVisitor<'tcx> {
         let const_kind = self
             .const_kind
             .expect("`const_check_violated` may only be called inside a const context");
-        let msg = format!("{} is not allowed in a `{}`", expr.name(), const_kind);
+
+        let msg = format!("{} is not allowed in a `{}`", expr.name(), const_kind.keyword_name());
 
         let required_gates = required_gates.unwrap_or(&[]);
         let missing_gates: Vec<_> =
@@ -191,7 +149,7 @@ impl<'tcx> CheckConstVisitor<'tcx> {
     }
 
     /// Saves the parent `const_kind` before calling `f` and restores it afterwards.
-    fn recurse_into(&mut self, kind: Option<ConstKind>, f: impl FnOnce(&mut Self)) {
+    fn recurse_into(&mut self, kind: Option<hir::ConstContext>, f: impl FnOnce(&mut Self)) {
         let parent_kind = self.const_kind;
         self.const_kind = kind;
         f(self);
@@ -207,12 +165,13 @@ impl<'tcx> Visitor<'tcx> for CheckConstVisitor<'tcx> {
     }
 
     fn visit_anon_const(&mut self, anon: &'tcx hir::AnonConst) {
-        let kind = Some(ConstKind::AnonConst);
+        let kind = Some(hir::ConstContext::Const);
         self.recurse_into(kind, |this| intravisit::walk_anon_const(this, anon));
     }
 
     fn visit_body(&mut self, body: &'tcx hir::Body<'tcx>) {
-        let kind = ConstKind::for_body(body, self.tcx);
+        let owner = self.tcx.hir().body_owner_def_id(body.id());
+        let kind = self.tcx.hir().body_const_context(owner);
         self.recurse_into(kind, |this| intravisit::walk_body(this, body));
     }