about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--compiler/rustc_const_eval/src/const_eval/eval_queries.rs13
-rw-r--r--compiler/rustc_const_eval/src/interpret/validity.rs28
-rw-r--r--tests/ui/consts/cycle-static-promoted.rs12
3 files changed, 29 insertions, 24 deletions
diff --git a/compiler/rustc_const_eval/src/const_eval/eval_queries.rs b/compiler/rustc_const_eval/src/const_eval/eval_queries.rs
index 0844cdbe99b..c55d899e4d5 100644
--- a/compiler/rustc_const_eval/src/const_eval/eval_queries.rs
+++ b/compiler/rustc_const_eval/src/const_eval/eval_queries.rs
@@ -356,22 +356,13 @@ pub fn const_validate_mplace<'mir, 'tcx>(
     let mut inner = false;
     while let Some((mplace, path)) = ref_tracking.todo.pop() {
         let mode = match ecx.tcx.static_mutability(cid.instance.def_id()) {
-            Some(_) if cid.promoted.is_some() => {
-                // Promoteds in statics are consts that re allowed to point to statics.
-                CtfeValidationMode::Const {
-                    allow_immutable_unsafe_cell: false,
-                    allow_extern_static_ptrs: true,
-                }
-            }
+            _ if cid.promoted.is_some() => CtfeValidationMode::Promoted,
             Some(mutbl) => CtfeValidationMode::Static { mutbl }, // a `static`
             None => {
                 // In normal `const` (not promoted), the outermost allocation is always only copied,
                 // so having `UnsafeCell` in there is okay despite them being in immutable memory.
                 let allow_immutable_unsafe_cell = cid.promoted.is_none() && !inner;
-                CtfeValidationMode::Const {
-                    allow_immutable_unsafe_cell,
-                    allow_extern_static_ptrs: false,
-                }
+                CtfeValidationMode::Const { allow_immutable_unsafe_cell }
             }
         };
         ecx.const_validate_operand(&mplace.into(), path, &mut ref_tracking, mode)?;
diff --git a/compiler/rustc_const_eval/src/interpret/validity.rs b/compiler/rustc_const_eval/src/interpret/validity.rs
index 38aeace02ba..05e28db652f 100644
--- a/compiler/rustc_const_eval/src/interpret/validity.rs
+++ b/compiler/rustc_const_eval/src/interpret/validity.rs
@@ -129,17 +129,20 @@ pub enum PathElem {
 pub enum CtfeValidationMode {
     /// Validation of a `static`
     Static { mutbl: Mutability },
-    /// Validation of a `const` (including promoteds).
+    /// Validation of a promoted.
+    Promoted,
+    /// Validation of a `const`.
     /// `allow_immutable_unsafe_cell` says whether we allow `UnsafeCell` in immutable memory (which is the
     /// case for the top-level allocation of a `const`, where this is fine because the allocation will be
     /// copied at each use site).
-    Const { allow_immutable_unsafe_cell: bool, allow_extern_static_ptrs: bool },
+    Const { allow_immutable_unsafe_cell: bool },
 }
 
 impl CtfeValidationMode {
     fn allow_immutable_unsafe_cell(self) -> bool {
         match self {
             CtfeValidationMode::Static { .. } => false,
+            CtfeValidationMode::Promoted { .. } => false,
             CtfeValidationMode::Const { allow_immutable_unsafe_cell, .. } => {
                 allow_immutable_unsafe_cell
             }
@@ -149,6 +152,7 @@ impl CtfeValidationMode {
     fn may_contain_mutable_ref(self) -> bool {
         match self {
             CtfeValidationMode::Static { mutbl } => mutbl == Mutability::Mut,
+            CtfeValidationMode::Promoted { .. } => false,
             CtfeValidationMode::Const { .. } => false,
         }
     }
@@ -476,34 +480,32 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValidityVisitor<'rt, 'mir, '
                                 throw_validation_failure!(self.path, MutableRefToImmutable);
                             }
                         }
+                        // Mode-specific checks
                         match self.ctfe_mode {
-                            Some(CtfeValidationMode::Static { .. }) => {
+                            Some(
+                                CtfeValidationMode::Static { .. }
+                                | CtfeValidationMode::Promoted { .. },
+                            ) => {
                                 // We skip recursively checking other statics. These statics must be sound by
                                 // themselves, and the only way to get broken statics here is by using
                                 // unsafe code.
                                 // The reasons we don't check other statics is twofold. For one, in all
                                 // sound cases, the static was already validated on its own, and second, we
                                 // trigger cycle errors if we try to compute the value of the other static
-                                // and that static refers back to us.
+                                // and that static refers back to us (potentially through a promoted).
                                 // This could miss some UB, but that's fine.
                                 return Ok(());
                             }
-                            Some(CtfeValidationMode::Const {
-                                allow_extern_static_ptrs, ..
-                            }) => {
+                            Some(CtfeValidationMode::Const { .. }) => {
                                 // For consts on the other hand we have to recursively check;
                                 // pattern matching assumes a valid value. However we better make
                                 // sure this is not mutable.
                                 if is_mut {
                                     throw_validation_failure!(self.path, ConstRefToMutable);
                                 }
+                                // We can't recursively validate `extern static`, so we better reject them.
                                 if self.ecx.tcx.is_foreign_item(did) {
-                                    if !allow_extern_static_ptrs {
-                                        throw_validation_failure!(self.path, ConstRefToExtern);
-                                    } else {
-                                        // We can't validate this...
-                                        return Ok(());
-                                    }
+                                    throw_validation_failure!(self.path, ConstRefToExtern);
                                 }
                             }
                             None => {}
diff --git a/tests/ui/consts/cycle-static-promoted.rs b/tests/ui/consts/cycle-static-promoted.rs
new file mode 100644
index 00000000000..5838dc58a3a
--- /dev/null
+++ b/tests/ui/consts/cycle-static-promoted.rs
@@ -0,0 +1,12 @@
+// check-pass
+
+struct Value {
+    values: &'static [&'static Value],
+}
+
+// This `static` recursively points to itself through a promoted (the slice).
+static VALUE: Value = Value {
+    values: &[&VALUE],
+};
+
+fn main() {}