about summary refs log tree commit diff
diff options
context:
space:
mode:
authorDylan MacKenzie <ecstaticmorse@gmail.com>2019-10-22 14:30:31 -0700
committerDylan MacKenzie <ecstaticmorse@gmail.com>2019-10-25 20:56:56 -0700
commitb2d021aa2b7c701406c10a3110dd31f990368c97 (patch)
tree81b4bb0a966b00743d73b2260c80879ff9b7699f
parent084edc426f2e7e4bbedb5c6afa7fc422a52ee379 (diff)
downloadrust-b2d021aa2b7c701406c10a3110dd31f990368c97.tar.gz
rust-b2d021aa2b7c701406c10a3110dd31f990368c97.zip
Make `check_consts::Item` work on non-const fns
This was originally only needed for validation, which is never run on
non-const `fn`s. The new promotion pass wants to use it, however.
-rw-r--r--src/librustc_mir/transform/check_consts/mod.rs98
-rw-r--r--src/librustc_mir/transform/check_consts/ops.rs33
-rw-r--r--src/librustc_mir/transform/check_consts/qualifs.rs21
-rw-r--r--src/librustc_mir/transform/check_consts/validation.rs71
-rw-r--r--src/librustc_mir/transform/promote_consts.rs2
5 files changed, 105 insertions, 120 deletions
diff --git a/src/librustc_mir/transform/check_consts/mod.rs b/src/librustc_mir/transform/check_consts/mod.rs
index 0c643f46243..61496ebb442 100644
--- a/src/librustc_mir/transform/check_consts/mod.rs
+++ b/src/librustc_mir/transform/check_consts/mod.rs
@@ -4,10 +4,12 @@
 //! has interior mutability or needs to be dropped, as well as the visitor that emits errors when
 //! it finds operations that are invalid in a certain context.
 
-use rustc::hir::def_id::DefId;
+use rustc::hir::{self, def_id::DefId};
 use rustc::mir;
 use rustc::ty::{self, TyCtxt};
 
+use std::fmt;
+
 pub use self::qualifs::Qualif;
 
 pub mod ops;
@@ -15,15 +17,14 @@ pub mod qualifs;
 mod resolver;
 pub mod validation;
 
-/// Information about the item currently being validated, as well as a reference to the global
+/// Information about the item currently being const-checked, as well as a reference to the global
 /// context.
 pub struct Item<'mir, 'tcx> {
     body: &'mir mir::Body<'tcx>,
     tcx: TyCtxt<'tcx>,
     def_id: DefId,
     param_env: ty::ParamEnv<'tcx>,
-    mode: validation::Mode,
-    for_promotion: bool,
+    const_kind: Option<ConstKind>,
 }
 
 impl Item<'mir, 'tcx> {
@@ -33,41 +34,88 @@ impl Item<'mir, 'tcx> {
         body: &'mir mir::Body<'tcx>,
     ) -> Self {
         let param_env = tcx.param_env(def_id);
-        let mode = validation::Mode::for_item(tcx, def_id)
-            .expect("const validation must only be run inside a const context");
+        let const_kind = ConstKind::for_item(tcx, def_id);
 
         Item {
             body,
             tcx,
             def_id,
             param_env,
-            mode,
-            for_promotion: false,
+            const_kind,
         }
     }
 
-    // HACK(eddyb) this is to get around the panic for a runtime fn from `Item::new`.
-    // Also, it allows promoting `&mut []`.
-    pub fn for_promotion(
-        tcx: TyCtxt<'tcx>,
-        def_id: DefId,
-        body: &'mir mir::Body<'tcx>,
-    ) -> Self {
-        let param_env = tcx.param_env(def_id);
-        let mode = validation::Mode::for_item(tcx, def_id)
-            .unwrap_or(validation::Mode::ConstFn);
+    /// 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 {
+        self.const_kind.expect("`const_kind` must not be called on a non-const fn")
+    }
+}
 
-        Item {
-            body,
-            tcx,
-            def_id,
-            param_env,
-            mode,
-            for_promotion: true,
+/// 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: DefId) -> Option<Self> {
+        use hir::BodyOwnerKind as HirKind;
+
+        let hir_id = tcx.hir().as_local_hir_id(def_id).unwrap();
+
+        let mode = match tcx.hir().body_owner_kind(hir_id) {
+            HirKind::Closure => return None,
+
+            HirKind::Fn if tcx.is_const_fn(def_id) => ConstKind::ConstFn,
+            HirKind::Fn => return None,
+
+            HirKind::Const => ConstKind::Const,
+
+            HirKind::Static(hir::MutImmutable) => ConstKind::Static,
+            HirKind::Static(hir::MutMutable) => ConstKind::StaticMut,
+        };
+
+        Some(mode)
+    }
+
+    pub fn is_static(self) -> bool {
+        match self {
+            ConstKind::Static | ConstKind::StaticMut => true,
+            ConstKind::ConstFn | ConstKind::Const => false,
+        }
+    }
+
+    /// Returns `true` if the value returned by this item must be `Sync`.
+    ///
+    /// This returns false for `StaticMut` since all accesses to one are `unsafe` anyway.
+    pub fn requires_sync(self) -> bool {
+        match self {
+            ConstKind::Static => true,
+            ConstKind::ConstFn | ConstKind::Const |  ConstKind::StaticMut => 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"),
+        }
+    }
+}
 
 fn is_lang_panic_fn(tcx: TyCtxt<'tcx>, def_id: DefId) -> bool {
     Some(def_id) == tcx.lang_items().panic_fn() ||
diff --git a/src/librustc_mir/transform/check_consts/ops.rs b/src/librustc_mir/transform/check_consts/ops.rs
index f457b739949..4b374cff809 100644
--- a/src/librustc_mir/transform/check_consts/ops.rs
+++ b/src/librustc_mir/transform/check_consts/ops.rs
@@ -8,8 +8,7 @@ use syntax::feature_gate::{emit_feature_err, GateIssue};
 use syntax::symbol::sym;
 use syntax_pos::{Span, Symbol};
 
-use super::Item;
-use super::validation::Mode;
+use super::{ConstKind, Item};
 
 /// An operation that is not *always* allowed in a const context.
 pub trait NonConstOp: std::fmt::Debug {
@@ -36,7 +35,7 @@ pub trait NonConstOp: std::fmt::Debug {
             span,
             E0019,
             "{} contains unimplemented expression type",
-            item.mode
+            item.const_kind()
         );
         if item.tcx.sess.teach(&err.get_code().unwrap()) {
             err.note("A function call isn't allowed in the const's initialization expression \
@@ -76,7 +75,7 @@ impl NonConstOp for FnCallNonConst {
             E0015,
             "calls in {}s are limited to constant functions, \
              tuple structs and tuple variants",
-            item.mode,
+            item.const_kind(),
         );
         err.emit();
     }
@@ -121,8 +120,8 @@ impl NonConstOp for HeapAllocation {
 
     fn emit_error(&self, item: &Item<'_, '_>, span: Span) {
         let mut err = struct_span_err!(item.tcx.sess, span, E0010,
-                                       "allocations are not allowed in {}s", item.mode);
-        err.span_label(span, format!("allocation not allowed in {}s", item.mode));
+                                       "allocations are not allowed in {}s", item.const_kind());
+        err.span_label(span, format!("allocation not allowed in {}s", item.const_kind()));
         if item.tcx.sess.teach(&err.get_code().unwrap()) {
             err.note(
                 "The value of statics and constants must be known at compile time, \
@@ -146,7 +145,7 @@ impl NonConstOp for LiveDrop {
         struct_span_err!(item.tcx.sess, span, E0493,
                          "destructors cannot be evaluated at compile-time")
             .span_label(span, format!("{}s cannot evaluate destructors",
-                                      item.mode))
+                                      item.const_kind()))
             .emit();
     }
 }
@@ -163,9 +162,9 @@ impl NonConstOp for MutBorrow {
         if let BorrowKind::Mut { .. } = kind {
             let mut err = struct_span_err!(item.tcx.sess, span, E0017,
                                            "references in {}s may only refer \
-                                            to immutable values", item.mode);
+                                            to immutable values", item.const_kind());
             err.span_label(span, format!("{}s require immutable values",
-                                                item.mode));
+                                                item.const_kind()));
             if item.tcx.sess.teach(&err.get_code().unwrap()) {
                 err.note("References in statics and constants may only refer \
                           to immutable values.\n\n\
@@ -202,7 +201,7 @@ impl NonConstOp for Panic {
             sym::const_panic,
             span,
             GateIssue::Language,
-            &format!("panicking in {}s is unstable", item.mode),
+            &format!("panicking in {}s is unstable", item.const_kind()),
         );
     }
 }
@@ -220,7 +219,7 @@ impl NonConstOp for RawPtrComparison {
             sym::const_compare_raw_pointers,
             span,
             GateIssue::Language,
-            &format!("comparing raw pointers inside {}", item.mode),
+            &format!("comparing raw pointers inside {}", item.const_kind()),
         );
     }
 }
@@ -238,7 +237,7 @@ impl NonConstOp for RawPtrDeref {
             span, GateIssue::Language,
             &format!(
                 "dereferencing raw pointers in {}s is unstable",
-                item.mode,
+                item.const_kind(),
             ),
         );
     }
@@ -257,7 +256,7 @@ impl NonConstOp for RawPtrToIntCast {
             span, GateIssue::Language,
             &format!(
                 "casting pointers to integers in {}s is unstable",
-                item.mode,
+                item.const_kind(),
             ),
         );
     }
@@ -268,13 +267,13 @@ impl NonConstOp for RawPtrToIntCast {
 pub struct StaticAccess;
 impl NonConstOp for StaticAccess {
     fn is_allowed_in_item(&self, item: &Item<'_, '_>) -> bool {
-        item.mode.is_static()
+        item.const_kind().is_static()
     }
 
     fn emit_error(&self, item: &Item<'_, '_>, span: Span) {
         let mut err = struct_span_err!(item.tcx.sess, span, E0013,
                                         "{}s cannot refer to statics, use \
-                                        a constant instead", item.mode);
+                                        a constant instead", item.const_kind());
         if item.tcx.sess.teach(&err.get_code().unwrap()) {
             err.note(
                 "Static and const variables can refer to other const variables. \
@@ -313,7 +312,7 @@ impl NonConstOp for Transmute {
             &item.tcx.sess.parse_sess, sym::const_transmute,
             span, GateIssue::Language,
             &format!("The use of std::mem::transmute() \
-            is gated in {}s", item.mode));
+            is gated in {}s", item.const_kind()));
     }
 }
 
@@ -322,7 +321,7 @@ pub struct UnionAccess;
 impl NonConstOp for UnionAccess {
     fn is_allowed_in_item(&self, item: &Item<'_, '_>) -> bool {
         // Union accesses are stable in all contexts except `const fn`.
-        item.mode != Mode::ConstFn || Self::feature_gate(item.tcx).unwrap()
+        item.const_kind() != ConstKind::ConstFn || Self::feature_gate(item.tcx).unwrap()
     }
 
     fn feature_gate(tcx: TyCtxt<'_>) -> Option<bool> {
diff --git a/src/librustc_mir/transform/check_consts/qualifs.rs b/src/librustc_mir/transform/check_consts/qualifs.rs
index e666dd9571f..840ad303016 100644
--- a/src/librustc_mir/transform/check_consts/qualifs.rs
+++ b/src/librustc_mir/transform/check_consts/qualifs.rs
@@ -5,8 +5,7 @@ use rustc::mir::interpret::ConstValue;
 use rustc::ty::{self, Ty};
 use syntax_pos::DUMMY_SP;
 
-use super::Item as ConstCx;
-use super::validation::Mode;
+use super::{ConstKind, Item as ConstCx};
 
 #[derive(Clone, Copy)]
 pub struct QualifSet(u8);
@@ -236,13 +235,17 @@ impl Qualif for HasMutInterior {
                     // mutably without consequences.
                     match ty.kind {
                         // Inside a `static mut`, &mut [...] is also allowed.
-                        ty::Array(..) | ty::Slice(_) if cx.mode == Mode::StaticMut => {},
-
-                        // FIXME(eddyb) the `cx.for_promotion` condition
-                        // seems unnecessary, given that this is merely a ZST.
-                        ty::Array(_, len)
-                            if len.try_eval_usize(cx.tcx, cx.param_env) == Some(0)
-                                && cx.for_promotion => {},
+                        | ty::Array(..)
+                        | ty::Slice(_)
+                        if cx.const_kind == Some(ConstKind::StaticMut)
+                        => {},
+
+                        // FIXME(eddyb): We only return false for `&mut []` outside a const
+                        // context which seems unnecessary given that this is merely a ZST.
+                        | ty::Array(_, len)
+                        if len.try_eval_usize(cx.tcx, cx.param_env) == Some(0)
+                            && cx.const_kind == None
+                        => {},
 
                         _ => return true,
                     }
diff --git a/src/librustc_mir/transform/check_consts/validation.rs b/src/librustc_mir/transform/check_consts/validation.rs
index fa746639736..c145fb41c96 100644
--- a/src/librustc_mir/transform/check_consts/validation.rs
+++ b/src/librustc_mir/transform/check_consts/validation.rs
@@ -1,10 +1,9 @@
 //! The `Visitor` responsible for actually checking a `mir::Body` for invalid operations.
 
-use rustc::hir::{self, def_id::DefId};
 use rustc::mir::visit::{PlaceContext, Visitor, MutatingUseContext, NonMutatingUseContext};
 use rustc::mir::*;
 use rustc::ty::cast::CastTy;
-use rustc::ty::{self, TyCtxt};
+use rustc::ty;
 use rustc_index::bit_set::BitSet;
 use rustc_target::spec::abi::Abi;
 use syntax::symbol::sym;
@@ -15,7 +14,7 @@ use std::fmt;
 use std::ops::Deref;
 
 use crate::dataflow as old_dataflow;
-use super::{Item, Qualif, is_lang_panic_fn};
+use super::{ConstKind, Item, Qualif, is_lang_panic_fn};
 use super::resolver::{FlowSensitiveResolver, IndirectlyMutableResults, QualifResolver};
 use super::qualifs::{HasMutInterior, NeedsDrop};
 use super::ops::{self, NonConstOp};
@@ -27,70 +26,6 @@ pub enum CheckOpResult {
     Allowed,
 }
 
-/// What kind of item we are in.
-#[derive(Copy, Clone, Debug, PartialEq, Eq)]
-pub enum Mode {
-    /// 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 Mode {
-    /// 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: DefId) -> Option<Self> {
-        use hir::BodyOwnerKind as HirKind;
-
-        let hir_id = tcx.hir().as_local_hir_id(def_id).unwrap();
-
-        let mode = match tcx.hir().body_owner_kind(hir_id) {
-            HirKind::Closure => return None,
-
-            HirKind::Fn if tcx.is_const_fn(def_id) => Mode::ConstFn,
-            HirKind::Fn => return None,
-
-            HirKind::Const => Mode::Const,
-
-            HirKind::Static(hir::MutImmutable) => Mode::Static,
-            HirKind::Static(hir::MutMutable) => Mode::StaticMut,
-        };
-
-        Some(mode)
-    }
-
-    pub fn is_static(self) -> bool {
-        match self {
-            Mode::Static | Mode::StaticMut => true,
-            Mode::ConstFn | Mode::Const => false,
-        }
-    }
-
-    /// Returns `true` if the value returned by this item must be `Sync`.
-    ///
-    /// This returns false for `StaticMut` since all accesses to one are `unsafe` anyway.
-    pub fn requires_sync(self) -> bool {
-        match self {
-            Mode::Static => true,
-            Mode::ConstFn | Mode::Const |  Mode::StaticMut => false,
-        }
-    }
-}
-
-impl fmt::Display for Mode {
-    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        match *self {
-            Mode::Const => write!(f, "constant"),
-            Mode::Static | Mode::StaticMut => write!(f, "static"),
-            Mode::ConstFn => write!(f, "constant function"),
-        }
-    }
-}
-
 pub struct Qualifs<'a, 'mir, 'tcx> {
     has_mut_interior: FlowSensitiveResolver<'a, 'mir, 'tcx, HasMutInterior>,
     needs_drop: FlowSensitiveResolver<'a, 'mir, 'tcx, NeedsDrop>,
@@ -343,7 +278,7 @@ impl Visitor<'tcx> for Validator<'_, 'mir, 'tcx> {
                 let is_thread_local = self.tcx.has_attr(*def_id, sym::thread_local);
                 if is_thread_local {
                     self.check_op(ops::ThreadLocalAccess);
-                } else if self.mode == Mode::Static && context.is_mutating_use() {
+                } else if self.const_kind() == ConstKind::Static && context.is_mutating_use() {
                     // this is not strictly necessary as miri will also bail out
                     // For interior mutability we can't really catch this statically as that
                     // goes through raw pointers and intermediate temporaries, so miri has
diff --git a/src/librustc_mir/transform/promote_consts.rs b/src/librustc_mir/transform/promote_consts.rs
index 7aaff5735f6..4bf1fc60fe7 100644
--- a/src/librustc_mir/transform/promote_consts.rs
+++ b/src/librustc_mir/transform/promote_consts.rs
@@ -730,7 +730,7 @@ pub fn validate_candidates(
         is_non_const_fn: false,
         temps,
 
-        const_cx: ConstCx::for_promotion(tcx, def_id, body),
+        const_cx: ConstCx::new(tcx, def_id, body),
 
         explicit: false,
     };