about summary refs log tree commit diff
diff options
context:
space:
mode:
authorOliver Scherer <github35764891676564198441@oli-obk.de>2019-12-25 13:58:02 +0100
committerOliver Scherer <github35764891676564198441@oli-obk.de>2020-01-15 10:48:22 +0100
commit10f439a0116df86f737d83cc620289b14c88660f (patch)
treebe574a3378413a0098399f9a2f0f5afa6e19a722
parent632387f38dfbac0f2b8b8900c840fff7f1fb888e (diff)
downloadrust-10f439a0116df86f737d83cc620289b14c88660f.tar.gz
rust-10f439a0116df86f737d83cc620289b14c88660f.zip
Promoteds can contain raw pointers, but these must still only point to immutable allocations
-rw-r--r--src/librustc_mir/const_eval.rs4
-rw-r--r--src/librustc_mir/const_eval/eval_queries.rs13
-rw-r--r--src/librustc_mir/interpret/intern.rs46
-rw-r--r--src/librustc_mir/interpret/mod.rs2
-rw-r--r--src/librustc_mir/transform/const_prop.rs8
-rw-r--r--src/test/ui/consts/raw_pointer_promoted.rs5
6 files changed, 56 insertions, 22 deletions
diff --git a/src/librustc_mir/const_eval.rs b/src/librustc_mir/const_eval.rs
index aa7be3d80e1..aad0e162935 100644
--- a/src/librustc_mir/const_eval.rs
+++ b/src/librustc_mir/const_eval.rs
@@ -5,7 +5,7 @@ use rustc::ty::layout::VariantIdx;
 use rustc::ty::{self, TyCtxt};
 use rustc_span::{source_map::DUMMY_SP, symbol::Symbol};
 
-use crate::interpret::{intern_const_alloc_recursive, ConstValue, InterpCx};
+use crate::interpret::{intern_const_alloc_recursive, ConstValue, InternKind, InterpCx};
 
 mod error;
 mod eval_queries;
@@ -52,7 +52,7 @@ pub(crate) fn const_caller_location<'tcx>(
 
     let loc_ty = tcx.caller_location_ty();
     let loc_place = ecx.alloc_caller_location(file, line, col);
-    intern_const_alloc_recursive(&mut ecx, None, loc_place, false).unwrap();
+    intern_const_alloc_recursive(&mut ecx, InternKind::Constant, loc_place, false).unwrap();
     let loc_const = ty::Const {
         ty: loc_ty,
         val: ty::ConstKind::Value(ConstValue::Scalar(loc_place.ptr.into())),
diff --git a/src/librustc_mir/const_eval/eval_queries.rs b/src/librustc_mir/const_eval/eval_queries.rs
index d260a6808d1..442baf85f2b 100644
--- a/src/librustc_mir/const_eval/eval_queries.rs
+++ b/src/librustc_mir/const_eval/eval_queries.rs
@@ -1,9 +1,9 @@
 use super::{error_to_const_error, CompileTimeEvalContext, CompileTimeInterpreter, MemoryExtra};
 use crate::interpret::eval_nullary_intrinsic;
 use crate::interpret::{
-    intern_const_alloc_recursive, Allocation, ConstValue, GlobalId, ImmTy, Immediate, InterpCx,
-    InterpResult, MPlaceTy, MemoryKind, OpTy, RawConst, RefTracking, Scalar, ScalarMaybeUndef,
-    StackPopCleanup,
+    intern_const_alloc_recursive, Allocation, ConstValue, GlobalId, ImmTy, Immediate, InternKind,
+    InterpCx, InterpResult, MPlaceTy, MemoryKind, OpTy, RawConst, RefTracking, Scalar,
+    ScalarMaybeUndef, StackPopCleanup,
 };
 use rustc::mir;
 use rustc::mir::interpret::{ConstEvalErr, ErrorHandled};
@@ -56,9 +56,14 @@ fn eval_body_using_ecx<'mir, 'tcx>(
     ecx.run()?;
 
     // Intern the result
+    let intern_kind = match tcx.static_mutability(cid.instance.def_id()) {
+        Some(m) => InternKind::Static(m),
+        None if cid.promoted.is_some() => InternKind::Promoted,
+        _ => InternKind::Constant,
+    };
     intern_const_alloc_recursive(
         ecx,
-        tcx.static_mutability(cid.instance.def_id()),
+        intern_kind,
         ret,
         body.ignore_interior_mut_in_const_validation,
     )?;
diff --git a/src/librustc_mir/interpret/intern.rs b/src/librustc_mir/interpret/intern.rs
index 220761ce28d..8ff78ffb5ba 100644
--- a/src/librustc_mir/interpret/intern.rs
+++ b/src/librustc_mir/interpret/intern.rs
@@ -268,19 +268,27 @@ impl<'rt, 'mir, 'tcx, M: CompileTimeMachine<'mir, 'tcx>> ValueVisitor<'mir, 'tcx
     }
 }
 
+pub enum InternKind {
+    /// The `mutability` of the static, ignoring the type which may have interior mutability.
+    Static(hir::Mutability),
+    Constant,
+    Promoted,
+    ConstProp,
+}
+
 pub fn intern_const_alloc_recursive<M: CompileTimeMachine<'mir, 'tcx>>(
     ecx: &mut InterpCx<'mir, 'tcx, M>,
-    // The `mutability` of the place, ignoring the type.
-    place_mut: Option<hir::Mutability>,
+    intern_kind: InternKind,
     ret: MPlaceTy<'tcx>,
     ignore_interior_mut_in_const_validation: bool,
 ) -> InterpResult<'tcx> {
     let tcx = ecx.tcx;
-    let (base_mutability, base_intern_mode) = match place_mut {
+    let (base_mutability, base_intern_mode) = match intern_kind {
         // `static mut` doesn't care about interior mutability, it's mutable anyway
-        Some(mutbl) => (mutbl, InternMode::Static),
-        // consts, promoteds. FIXME: what about array lengths, array initializers?
-        None => (Mutability::Not, InternMode::ConstBase),
+        InternKind::Static(mutbl) => (mutbl, InternMode::Static),
+        // FIXME: what about array lengths, array initializers?
+        InternKind::Constant | InternKind::ConstProp => (Mutability::Not, InternMode::ConstBase),
+        InternKind::Promoted => (Mutability::Not, InternMode::ConstBase),
     };
 
     // Type based interning.
@@ -338,10 +346,23 @@ pub fn intern_const_alloc_recursive<M: CompileTimeMachine<'mir, 'tcx>>(
             // We can't call the `intern_shallow` method here, as its logic is tailored to safe
             // references and a `leftover_allocations` set (where we only have a todo-list here).
             // So we hand-roll the interning logic here again.
-            match base_intern_mode {
-                InternMode::Static => {}
-                InternMode::Const | InternMode::ConstBase => {
-                    // If it's not a static, it *must* be immutable.
+            match intern_kind {
+                // Mutable statics may contain mutable allocations even behind relocations
+                InternKind::Static(hir::Mutability::Mut) => {}
+                // Once we get heap allocations we need to revisit whether immutable statics can
+                // refer to mutable (e.g. via interior mutability) allocations.
+                InternKind::Static(hir::Mutability::Not) => {
+                    alloc.mutability = Mutability::Not;
+                }
+                // Raw pointers in promoteds may only point to immutable things so we mark
+                // everything as immutable. Creating a promoted with interior mutability is UB, but
+                // there's no way we can check whether the user is using raw pointers correctly.
+                // So all we can do is mark this as immutable here.
+                InternKind::Promoted => {
+                    alloc.mutability = Mutability::Not;
+                }
+                InternKind::Constant | InternKind::ConstProp => {
+                    // If it's a constant, it *must* be immutable.
                     // We cannot have mutable memory inside a constant.
                     // We use `delay_span_bug` here, because this can be reached in the presence
                     // of fancy transmutes.
@@ -363,7 +384,10 @@ pub fn intern_const_alloc_recursive<M: CompileTimeMachine<'mir, 'tcx>>(
         } else if ecx.memory.dead_alloc_map.contains_key(&alloc_id) {
             // dangling pointer
             throw_unsup!(ValidationFailure("encountered dangling pointer in final constant".into()))
-        } else if ecx.tcx.alloc_map.lock().get(alloc_id).is_none() {
+        } else if let Some(_) = ecx.tcx.alloc_map.lock().get(alloc_id) {
+            // FIXME: check if the allocation is ok as per the interning rules as if we interned
+            // it right here.
+        } else {
             span_bug!(ecx.tcx.span, "encountered unknown alloc id {:?}", alloc_id);
         }
     }
diff --git a/src/librustc_mir/interpret/mod.rs b/src/librustc_mir/interpret/mod.rs
index 2e8fbb95ca2..a519f38e712 100644
--- a/src/librustc_mir/interpret/mod.rs
+++ b/src/librustc_mir/interpret/mod.rs
@@ -32,6 +32,6 @@ pub use self::visitor::{MutValueVisitor, ValueVisitor};
 
 pub use self::validity::RefTracking;
 
-pub use self::intern::intern_const_alloc_recursive;
+pub use self::intern::{intern_const_alloc_recursive, InternKind};
 
 crate use self::intrinsics::eval_nullary_intrinsic;
diff --git a/src/librustc_mir/transform/const_prop.rs b/src/librustc_mir/transform/const_prop.rs
index 1d5a643484a..7dd82e6a6f9 100644
--- a/src/librustc_mir/transform/const_prop.rs
+++ b/src/librustc_mir/transform/const_prop.rs
@@ -29,9 +29,9 @@ use syntax::ast::Mutability;
 
 use crate::const_eval::error_to_const_error;
 use crate::interpret::{
-    self, intern_const_alloc_recursive, AllocId, Allocation, Frame, ImmTy, Immediate, InterpCx,
-    LocalState, LocalValue, Memory, MemoryKind, OpTy, Operand as InterpOperand, PlaceTy, Pointer,
-    ScalarMaybeUndef, StackPopCleanup,
+    self, intern_const_alloc_recursive, AllocId, Allocation, Frame, ImmTy, Immediate, InternKind,
+    InterpCx, LocalState, LocalValue, Memory, MemoryKind, OpTy, Operand as InterpOperand, PlaceTy,
+    Pointer, ScalarMaybeUndef, StackPopCleanup,
 };
 use crate::transform::{MirPass, MirSource};
 
@@ -726,7 +726,7 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> {
             )) => l.is_bits() && r.is_bits(),
             interpret::Operand::Indirect(_) if mir_opt_level >= 2 => {
                 let mplace = op.assert_mem_place(&self.ecx);
-                intern_const_alloc_recursive(&mut self.ecx, None, mplace, false)
+                intern_const_alloc_recursive(&mut self.ecx, InternKind::ConstProp, mplace, false)
                     .expect("failed to intern alloc");
                 true
             }
diff --git a/src/test/ui/consts/raw_pointer_promoted.rs b/src/test/ui/consts/raw_pointer_promoted.rs
new file mode 100644
index 00000000000..4c62ad444a5
--- /dev/null
+++ b/src/test/ui/consts/raw_pointer_promoted.rs
@@ -0,0 +1,5 @@
+// check-pass
+
+pub const FOO: &'static *const i32 = &(&0 as _);
+
+fn main() {}