-
Notifications
You must be signed in to change notification settings - Fork 13.6k
const interning: decide about mutability purely based on the kind of interning, not the types we see #116745
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
const interning: decide about mutability purely based on the kind of interning, not the types we see #116745
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Large diffs are not rendered by default.
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -9,12 +9,13 @@ use std::num::NonZeroUsize; | |
|
||
use either::{Left, Right}; | ||
|
||
use hir::def::DefKind; | ||
use rustc_ast::Mutability; | ||
use rustc_data_structures::fx::FxHashSet; | ||
use rustc_hir as hir; | ||
use rustc_middle::mir::interpret::{ | ||
ExpectedKind, InterpError, InvalidMetaKind, Misalignment, PointerKind, ValidationErrorInfo, | ||
ValidationErrorKind, ValidationErrorKind::*, | ||
ExpectedKind, InterpError, InvalidMetaKind, Misalignment, PointerKind, Provenance, | ||
ValidationErrorInfo, ValidationErrorKind, ValidationErrorKind::*, | ||
}; | ||
use rustc_middle::ty; | ||
use rustc_middle::ty::layout::{LayoutOf, TyAndLayout}; | ||
|
@@ -123,15 +124,41 @@ pub enum PathElem { | |
} | ||
|
||
/// Extra things to check for during validation of CTFE results. | ||
#[derive(Copy, Clone)] | ||
pub enum CtfeValidationMode { | ||
/// Regular validation, nothing special happening. | ||
Regular, | ||
/// Validation of a `const`. | ||
/// `inner` says if this is an inner, indirect allocation (as opposed to the top-level const | ||
/// allocation). Being an inner allocation makes a difference because the top-level allocation | ||
/// of a `const` is copied for each use, but the inner allocations are implicitly shared. | ||
/// Validation of a `static` | ||
Static { mutbl: Mutability }, | ||
/// Validation of a `const` (including promoteds). | ||
/// `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). | ||
/// `allow_static_ptrs` says if pointers to statics are permitted (which is the case for promoteds in statics). | ||
Const { inner: bool, allow_static_ptrs: bool }, | ||
Const { allow_immutable_unsafe_cell: bool, allow_static_ptrs: bool }, | ||
} | ||
|
||
impl CtfeValidationMode { | ||
fn allow_immutable_unsafe_cell(self) -> bool { | ||
match self { | ||
CtfeValidationMode::Static { .. } => false, | ||
CtfeValidationMode::Const { allow_immutable_unsafe_cell, .. } => { | ||
allow_immutable_unsafe_cell | ||
} | ||
} | ||
} | ||
|
||
fn allow_static_ptrs(self) -> bool { | ||
match self { | ||
CtfeValidationMode::Static { .. } => true, // statics can point to statics | ||
CtfeValidationMode::Const { allow_static_ptrs, .. } => allow_static_ptrs, | ||
} | ||
} | ||
|
||
fn may_contain_mutable_ref(self) -> bool { | ||
match self { | ||
CtfeValidationMode::Static { mutbl } => mutbl == Mutability::Mut, | ||
CtfeValidationMode::Const { .. } => false, | ||
} | ||
} | ||
} | ||
|
||
/// State for tracking recursive validation of references | ||
|
@@ -418,6 +445,22 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValidityVisitor<'rt, 'mir, ' | |
} | ||
// Recursive checking | ||
if let Some(ref_tracking) = self.ref_tracking.as_deref_mut() { | ||
// Determine whether this pointer expects to be pointing to something mutable. | ||
let ptr_expected_mutbl = match ptr_kind { | ||
PointerKind::Box => Mutability::Mut, | ||
PointerKind::Ref => { | ||
let tam = value.layout.ty.builtin_deref(false).unwrap(); | ||
// ZST never require mutability. We do not take into account interior mutability | ||
// here since we cannot know if there really is an `UnsafeCell` inside | ||
// `Option<UnsafeCell>` -- so we check that in the recursive descent behind this | ||
// reference. | ||
if size == Size::ZERO || tam.mutbl == Mutability::Not { | ||
Mutability::Not | ||
} else { | ||
Mutability::Mut | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We could have an extra check for |
||
} | ||
} | ||
}; | ||
// Proceed recursively even for ZST, no reason to skip them! | ||
// `!` is a ZST and we want to validate it. | ||
if let Ok((alloc_id, _offset, _prov)) = self.ecx.ptr_try_get_alloc_id(place.ptr()) { | ||
|
@@ -428,16 +471,29 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValidityVisitor<'rt, 'mir, ' | |
// Special handling for pointers to statics (irrespective of their type). | ||
assert!(!self.ecx.tcx.is_thread_local_static(did)); | ||
assert!(self.ecx.tcx.is_static(did)); | ||
if matches!( | ||
self.ctfe_mode, | ||
Some(CtfeValidationMode::Const { allow_static_ptrs: false, .. }) | ||
) { | ||
if self.ctfe_mode.is_some_and(|c| !c.allow_static_ptrs()) { | ||
// See const_eval::machine::MemoryExtra::can_access_statics for why | ||
// this check is so important. | ||
// This check is reachable when the const just referenced the static, | ||
// but never read it (so we never entered `before_access_global`). | ||
throw_validation_failure!(self.path, PtrToStatic { ptr_kind }); | ||
} | ||
// Mutability check. | ||
if ptr_expected_mutbl == Mutability::Mut { | ||
if matches!( | ||
self.ecx.tcx.def_kind(did), | ||
DefKind::Static(Mutability::Not) | ||
) && self | ||
.ecx | ||
.tcx | ||
.type_of(did) | ||
.no_bound_vars() | ||
.expect("statics should not have generic parameters") | ||
.is_freeze(*self.ecx.tcx, ty::ParamEnv::reveal_all()) | ||
{ | ||
throw_validation_failure!(self.path, MutableRefToImmutable); | ||
} | ||
} | ||
// 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. | ||
|
@@ -454,14 +510,29 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValidityVisitor<'rt, 'mir, ' | |
if alloc.inner().mutability == Mutability::Mut | ||
&& matches!(self.ctfe_mode, Some(CtfeValidationMode::Const { .. })) | ||
{ | ||
// This should be unreachable, but if someone manages to copy a pointer | ||
// out of a `static`, then that pointer might point to mutable memory, | ||
// and we would catch that here. | ||
throw_validation_failure!(self.path, PtrToMut { ptr_kind }); | ||
// This is impossible: this can only be some inner allocation of a | ||
// `static mut` (everything else either hits the `GlobalAlloc::Static` | ||
// case or is interned immutably). To get such a pointer we'd have to | ||
// load it from a static, but such loads lead to a CTFE error. | ||
span_bug!( | ||
self.ecx.tcx.span, | ||
"encountered reference to mutable memory inside a `const`" | ||
); | ||
} | ||
if ptr_expected_mutbl == Mutability::Mut | ||
&& alloc.inner().mutability == Mutability::Not | ||
{ | ||
throw_validation_failure!(self.path, MutableRefToImmutable); | ||
} | ||
} | ||
// Nothing to check for these. | ||
None | Some(GlobalAlloc::Function(..) | GlobalAlloc::VTable(..)) => {} | ||
Some(GlobalAlloc::Function(..) | GlobalAlloc::VTable(..)) => { | ||
// These are immutable, we better don't allow mutable pointers here. | ||
if ptr_expected_mutbl == Mutability::Mut { | ||
throw_validation_failure!(self.path, MutableRefToImmutable); | ||
} | ||
} | ||
// Dangling, already handled. | ||
None => bug!(), | ||
} | ||
} | ||
let path = &self.path; | ||
|
@@ -532,11 +603,9 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValidityVisitor<'rt, 'mir, ' | |
Ok(true) | ||
} | ||
ty::Ref(_, ty, mutbl) => { | ||
if matches!(self.ctfe_mode, Some(CtfeValidationMode::Const { .. })) | ||
if self.ctfe_mode.is_some_and(|c| !c.may_contain_mutable_ref()) | ||
&& *mutbl == Mutability::Mut | ||
{ | ||
// A mutable reference inside a const? That does not seem right (except if it is | ||
// a ZST). | ||
let layout = self.ecx.layout_of(*ty)?; | ||
if !layout.is_zst() { | ||
throw_validation_failure!(self.path, MutableRefInConst); | ||
|
@@ -642,6 +711,19 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValidityVisitor<'rt, 'mir, ' | |
) | ||
} | ||
} | ||
|
||
fn in_mutable_memory(&self, op: &OpTy<'tcx, M::Provenance>) -> bool { | ||
if let Some(mplace) = op.as_mplace_or_imm().left() { | ||
if let Some(alloc_id) = mplace.ptr().provenance.and_then(|p| p.get_alloc_id()) { | ||
if self.ecx.tcx.global_alloc(alloc_id).unwrap_memory().inner().mutability | ||
== Mutability::Mut | ||
{ | ||
return true; | ||
} | ||
} | ||
} | ||
false | ||
} | ||
} | ||
|
||
impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValueVisitor<'mir, 'tcx, M> | ||
|
@@ -705,10 +787,12 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValueVisitor<'mir, 'tcx, M> | |
op: &OpTy<'tcx, M::Provenance>, | ||
_fields: NonZeroUsize, | ||
) -> InterpResult<'tcx> { | ||
// Special check preventing `UnsafeCell` inside unions in the inner part of constants. | ||
if matches!(self.ctfe_mode, Some(CtfeValidationMode::Const { inner: true, .. })) { | ||
if !op.layout.ty.is_freeze(*self.ecx.tcx, self.ecx.param_env) { | ||
throw_validation_failure!(self.path, UnsafeCell); | ||
// Special check for CTFE validation, preventing `UnsafeCell` inside unions in immutable memory. | ||
if self.ctfe_mode.is_some_and(|c| !c.allow_immutable_unsafe_cell()) { | ||
if !op.layout.is_zst() && !op.layout.ty.is_freeze(*self.ecx.tcx, self.ecx.param_env) { | ||
if !self.in_mutable_memory(op) { | ||
throw_validation_failure!(self.path, UnsafeCellInImmutable); | ||
} | ||
} | ||
} | ||
Ok(()) | ||
|
@@ -730,11 +814,14 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValueVisitor<'mir, 'tcx, M> | |
} | ||
|
||
// Special check preventing `UnsafeCell` in the inner part of constants | ||
if let Some(def) = op.layout.ty.ty_adt_def() { | ||
if matches!(self.ctfe_mode, Some(CtfeValidationMode::Const { inner: true, .. })) | ||
if self.ctfe_mode.is_some_and(|c| !c.allow_immutable_unsafe_cell()) { | ||
if !op.layout.is_zst() | ||
&& let Some(def) = op.layout.ty.ty_adt_def() | ||
&& def.is_unsafe_cell() | ||
{ | ||
throw_validation_failure!(self.path, UnsafeCell); | ||
if !self.in_mutable_memory(op) { | ||
throw_validation_failure!(self.path, UnsafeCellInImmutable); | ||
} | ||
} | ||
} | ||
|
||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,14 +1,14 @@ | ||
#![feature(raw_ref_op)] | ||
|
||
const A: () = { let mut x = 2; &raw mut x; }; //~ mutable reference | ||
const A: () = { let mut x = 2; &raw mut x; }; //~ mutable pointer | ||
|
||
static B: () = { let mut x = 2; &raw mut x; }; //~ mutable reference | ||
static B: () = { let mut x = 2; &raw mut x; }; //~ mutable pointer | ||
|
||
static mut C: () = { let mut x = 2; &raw mut x; }; //~ mutable reference | ||
static mut C: () = { let mut x = 2; &raw mut x; }; //~ mutable pointer | ||
|
||
const fn foo() { | ||
let mut x = 0; | ||
let y = &raw mut x; //~ mutable reference | ||
let y = &raw mut x; //~ mutable pointer | ||
} | ||
|
||
fn main() {} |
This file was deleted.
This file was deleted.
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,10 +1,8 @@ | ||
error: unsupported untyped pointer in constant | ||
error: encountered mutable pointer in final value of constant | ||
--> $DIR/alloc_intrinsic_untyped.rs:6:1 | ||
| | ||
LL | const BAR: *mut i32 = unsafe { intrinsics::const_allocate(4, 4) as *mut i32 }; | ||
| ^^^^^^^^^^^^^^^^^^^ | ||
| | ||
= note: memory only reachable via raw pointers is not supported | ||
|
||
error: aborting due to 1 previous error | ||
|
This file was deleted.
This file was deleted.
This file was deleted.
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,54 +1,177 @@ | ||
error[E0080]: it is undefined behavior to use this value | ||
--> $DIR/mutable_references_err.rs:15:1 | ||
error: encountered mutable pointer in final value of constant | ||
--> $DIR/mutable_references_err.rs:17:1 | ||
| | ||
LL | const MUH: Meh = Meh { | ||
| ^^^^^^^^^^^^^^ constructing invalid value at .x.<deref>: encountered `UnsafeCell` in a `const` | ||
| ^^^^^^^^^^^^^^ | ||
|
||
error: encountered mutable pointer in final value of constant | ||
--> $DIR/mutable_references_err.rs:27:1 | ||
| | ||
LL | const SNEAKY: &dyn Sync = &Synced { x: UnsafeCell::new(42) }; | ||
| ^^^^^^^^^^^^^^^^^^^^^^^ | ||
|
||
error[E0080]: it is undefined behavior to use this value | ||
--> $DIR/mutable_references_err.rs:32:1 | ||
| | ||
LL | const SUBTLE: &mut i32 = unsafe { &mut FOO }; | ||
| ^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered mutable reference in a `const` or `static` | ||
| | ||
= note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. | ||
= note: the raw bytes of the constant (size: 4, align: 4) { | ||
╾ALLOC0╼ │ ╾──╼ | ||
} | ||
|
||
error: encountered mutable pointer in final value of constant | ||
--> $DIR/mutable_references_err.rs:35:1 | ||
| | ||
LL | const BLUNT: &mut i32 = &mut 42; | ||
| ^^^^^^^^^^^^^^^^^^^^^ | ||
|
||
error[E0080]: it is undefined behavior to use this value | ||
--> $DIR/mutable_references_err.rs:25:1 | ||
--> $DIR/mutable_references_err.rs:40:1 | ||
| | ||
LL | const SNEAKY: &dyn Sync = &Synced { x: UnsafeCell::new(42) }; | ||
| ^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .<deref>.<dyn-downcast>.x: encountered `UnsafeCell` in a `const` | ||
LL | static mut MUT_TO_READONLY: &mut i32 = unsafe { &mut *(&READONLY as *const _ as *mut _) }; | ||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered mutable reference or box pointing to read-only memory | ||
| | ||
= note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. | ||
= note: the raw bytes of the constant (size: 8, align: 4) { | ||
╾ALLOC1╼ ╾ALLOC2╼ │ ╾──╼╾──╼ | ||
= note: the raw bytes of the constant (size: 4, align: 4) { | ||
╾ALLOC1<imm>╼ │ ╾──╼ | ||
} | ||
|
||
error[E0080]: it is undefined behavior to use this value | ||
--> $DIR/mutable_references_err.rs:29:1 | ||
--> $DIR/mutable_references_err.rs:47:1 | ||
| | ||
LL | const BLUNT: &mut i32 = &mut 42; | ||
| ^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered mutable reference in a `const` | ||
LL | const POINTS_TO_MUTABLE1: &i32 = unsafe { &MUTABLE }; | ||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered a reference pointing to a static variable in a constant | ||
| | ||
= note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. | ||
= note: the raw bytes of the constant (size: 4, align: 4) { | ||
╾ALLOC3╼ │ ╾──╼ | ||
╾ALLOC2<imm>╼ │ ╾──╼ | ||
} | ||
|
||
error[E0080]: evaluation of constant value failed | ||
--> $DIR/mutable_references_err.rs:51:43 | ||
| | ||
LL | const POINTS_TO_MUTABLE2: &i32 = unsafe { &*MUTABLE_REF }; | ||
| ^^^^^^^^^^^^^ constant accesses static | ||
|
||
error: encountered mutable pointer in final value of constant | ||
--> $DIR/mutable_references_err.rs:55:1 | ||
| | ||
LL | const POINTS_TO_MUTABLE_INNER: *const i32 = &mut 42 as *mut _ as *const _; | ||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | ||
|
||
error: encountered mutable pointer in final value of constant | ||
--> $DIR/mutable_references_err.rs:65:1 | ||
| | ||
LL | const RAW_SYNC: SyncPtr<AtomicI32> = SyncPtr { x: &AtomicI32::new(42) }; | ||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | ||
|
||
error: encountered mutable pointer in final value of constant | ||
--> $DIR/mutable_references_err.rs:67:1 | ||
| | ||
LL | const RAW_MUT_CAST: SyncPtr<i32> = SyncPtr { x : &mut 42 as *mut _ as *const _ }; | ||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | ||
|
||
error: encountered mutable pointer in final value of constant | ||
--> $DIR/mutable_references_err.rs:69:1 | ||
| | ||
LL | const RAW_MUT_COERCE: SyncPtr<i32> = SyncPtr { x: &mut 0 }; | ||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | ||
|
||
warning: skipping const checks | ||
| | ||
help: skipping check that does not even have a feature gate | ||
--> $DIR/mutable_references_err.rs:16:8 | ||
--> $DIR/mutable_references_err.rs:18:8 | ||
| | ||
LL | x: &UnsafeCell::new(42), | ||
| ^^^^^^^^^^^^^^^^^^^^ | ||
help: skipping check that does not even have a feature gate | ||
--> $DIR/mutable_references_err.rs:25:27 | ||
--> $DIR/mutable_references_err.rs:27:27 | ||
| | ||
LL | const SNEAKY: &dyn Sync = &Synced { x: UnsafeCell::new(42) }; | ||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | ||
help: skipping check that does not even have a feature gate | ||
--> $DIR/mutable_references_err.rs:29:25 | ||
--> $DIR/mutable_references_err.rs:32:40 | ||
| | ||
LL | const SUBTLE: &mut i32 = unsafe { &mut FOO }; | ||
| ^^^ | ||
help: skipping check that does not even have a feature gate | ||
--> $DIR/mutable_references_err.rs:32:40 | ||
| | ||
LL | const SUBTLE: &mut i32 = unsafe { &mut FOO }; | ||
| ^^^ | ||
help: skipping check that does not even have a feature gate | ||
--> $DIR/mutable_references_err.rs:32:35 | ||
| | ||
LL | const SUBTLE: &mut i32 = unsafe { &mut FOO }; | ||
| ^^^^^^^^ | ||
help: skipping check that does not even have a feature gate | ||
--> $DIR/mutable_references_err.rs:35:25 | ||
| | ||
LL | const BLUNT: &mut i32 = &mut 42; | ||
| ^^^^^^^ | ||
help: skipping check for `const_mut_refs` feature | ||
--> $DIR/mutable_references_err.rs:40:49 | ||
| | ||
LL | static mut MUT_TO_READONLY: &mut i32 = unsafe { &mut *(&READONLY as *const _ as *mut _) }; | ||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | ||
help: skipping check for `const_mut_refs` feature | ||
--> $DIR/mutable_references_err.rs:40:49 | ||
| | ||
LL | static mut MUT_TO_READONLY: &mut i32 = unsafe { &mut *(&READONLY as *const _ as *mut _) }; | ||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | ||
help: skipping check that does not even have a feature gate | ||
--> $DIR/mutable_references_err.rs:40:49 | ||
| | ||
LL | static mut MUT_TO_READONLY: &mut i32 = unsafe { &mut *(&READONLY as *const _ as *mut _) }; | ||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | ||
help: skipping check that does not even have a feature gate | ||
--> $DIR/mutable_references_err.rs:47:44 | ||
| | ||
LL | const POINTS_TO_MUTABLE1: &i32 = unsafe { &MUTABLE }; | ||
| ^^^^^^^ | ||
help: skipping check that does not even have a feature gate | ||
--> $DIR/mutable_references_err.rs:47:44 | ||
| | ||
LL | const POINTS_TO_MUTABLE1: &i32 = unsafe { &MUTABLE }; | ||
| ^^^^^^^ | ||
help: skipping check that does not even have a feature gate | ||
--> $DIR/mutable_references_err.rs:50:36 | ||
| | ||
LL | static mut MUTABLE_REF: &mut i32 = &mut 42; | ||
| ^^^^^^^ | ||
help: skipping check that does not even have a feature gate | ||
--> $DIR/mutable_references_err.rs:51:45 | ||
| | ||
LL | const POINTS_TO_MUTABLE2: &i32 = unsafe { &*MUTABLE_REF }; | ||
| ^^^^^^^^^^^ | ||
help: skipping check that does not even have a feature gate | ||
--> $DIR/mutable_references_err.rs:51:45 | ||
| | ||
LL | const POINTS_TO_MUTABLE2: &i32 = unsafe { &*MUTABLE_REF }; | ||
| ^^^^^^^^^^^ | ||
help: skipping check that does not even have a feature gate | ||
--> $DIR/mutable_references_err.rs:55:45 | ||
| | ||
LL | const POINTS_TO_MUTABLE_INNER: *const i32 = &mut 42 as *mut _ as *const _; | ||
| ^^^^^^^ | ||
help: skipping check that does not even have a feature gate | ||
--> $DIR/mutable_references_err.rs:65:51 | ||
| | ||
LL | const RAW_SYNC: SyncPtr<AtomicI32> = SyncPtr { x: &AtomicI32::new(42) }; | ||
| ^^^^^^^^^^^^^^^^^^^ | ||
help: skipping check that does not even have a feature gate | ||
--> $DIR/mutable_references_err.rs:67:50 | ||
| | ||
LL | const RAW_MUT_CAST: SyncPtr<i32> = SyncPtr { x : &mut 42 as *mut _ as *const _ }; | ||
| ^^^^^^^ | ||
help: skipping check that does not even have a feature gate | ||
--> $DIR/mutable_references_err.rs:69:51 | ||
| | ||
LL | const RAW_MUT_COERCE: SyncPtr<i32> = SyncPtr { x: &mut 0 }; | ||
| ^^^^^^ | ||
|
||
error: aborting due to 3 previous errors; 1 warning emitted | ||
error: aborting due to 11 previous errors; 1 warning emitted | ||
|
||
For more information about this error, try `rustc --explain E0080`. |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,54 +1,177 @@ | ||
error[E0080]: it is undefined behavior to use this value | ||
--> $DIR/mutable_references_err.rs:15:1 | ||
error: encountered mutable pointer in final value of constant | ||
--> $DIR/mutable_references_err.rs:17:1 | ||
| | ||
LL | const MUH: Meh = Meh { | ||
| ^^^^^^^^^^^^^^ constructing invalid value at .x.<deref>: encountered `UnsafeCell` in a `const` | ||
| ^^^^^^^^^^^^^^ | ||
|
||
error: encountered mutable pointer in final value of constant | ||
--> $DIR/mutable_references_err.rs:27:1 | ||
| | ||
LL | const SNEAKY: &dyn Sync = &Synced { x: UnsafeCell::new(42) }; | ||
| ^^^^^^^^^^^^^^^^^^^^^^^ | ||
|
||
error[E0080]: it is undefined behavior to use this value | ||
--> $DIR/mutable_references_err.rs:32:1 | ||
| | ||
LL | const SUBTLE: &mut i32 = unsafe { &mut FOO }; | ||
| ^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered mutable reference in a `const` or `static` | ||
| | ||
= note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. | ||
= note: the raw bytes of the constant (size: 8, align: 8) { | ||
╾ALLOC0╼ │ ╾──────╼ | ||
} | ||
|
||
error: encountered mutable pointer in final value of constant | ||
--> $DIR/mutable_references_err.rs:35:1 | ||
| | ||
LL | const BLUNT: &mut i32 = &mut 42; | ||
| ^^^^^^^^^^^^^^^^^^^^^ | ||
|
||
error[E0080]: it is undefined behavior to use this value | ||
--> $DIR/mutable_references_err.rs:25:1 | ||
--> $DIR/mutable_references_err.rs:40:1 | ||
| | ||
LL | const SNEAKY: &dyn Sync = &Synced { x: UnsafeCell::new(42) }; | ||
| ^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .<deref>.<dyn-downcast>.x: encountered `UnsafeCell` in a `const` | ||
LL | static mut MUT_TO_READONLY: &mut i32 = unsafe { &mut *(&READONLY as *const _ as *mut _) }; | ||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered mutable reference or box pointing to read-only memory | ||
| | ||
= note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. | ||
= note: the raw bytes of the constant (size: 16, align: 8) { | ||
╾ALLOC1╼ ╾ALLOC2╼ │ ╾──────╼╾──────╼ | ||
= note: the raw bytes of the constant (size: 8, align: 8) { | ||
╾ALLOC1<imm>╼ │ ╾──────╼ | ||
} | ||
|
||
error[E0080]: it is undefined behavior to use this value | ||
--> $DIR/mutable_references_err.rs:29:1 | ||
--> $DIR/mutable_references_err.rs:47:1 | ||
| | ||
LL | const BLUNT: &mut i32 = &mut 42; | ||
| ^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered mutable reference in a `const` | ||
LL | const POINTS_TO_MUTABLE1: &i32 = unsafe { &MUTABLE }; | ||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered a reference pointing to a static variable in a constant | ||
| | ||
= note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. | ||
= note: the raw bytes of the constant (size: 8, align: 8) { | ||
╾ALLOC3╼ │ ╾──────╼ | ||
╾ALLOC2<imm>╼ │ ╾──────╼ | ||
} | ||
|
||
error[E0080]: evaluation of constant value failed | ||
--> $DIR/mutable_references_err.rs:51:43 | ||
| | ||
LL | const POINTS_TO_MUTABLE2: &i32 = unsafe { &*MUTABLE_REF }; | ||
| ^^^^^^^^^^^^^ constant accesses static | ||
|
||
error: encountered mutable pointer in final value of constant | ||
--> $DIR/mutable_references_err.rs:55:1 | ||
| | ||
LL | const POINTS_TO_MUTABLE_INNER: *const i32 = &mut 42 as *mut _ as *const _; | ||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | ||
|
||
error: encountered mutable pointer in final value of constant | ||
--> $DIR/mutable_references_err.rs:65:1 | ||
| | ||
LL | const RAW_SYNC: SyncPtr<AtomicI32> = SyncPtr { x: &AtomicI32::new(42) }; | ||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | ||
|
||
error: encountered mutable pointer in final value of constant | ||
--> $DIR/mutable_references_err.rs:67:1 | ||
| | ||
LL | const RAW_MUT_CAST: SyncPtr<i32> = SyncPtr { x : &mut 42 as *mut _ as *const _ }; | ||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | ||
|
||
error: encountered mutable pointer in final value of constant | ||
--> $DIR/mutable_references_err.rs:69:1 | ||
| | ||
LL | const RAW_MUT_COERCE: SyncPtr<i32> = SyncPtr { x: &mut 0 }; | ||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | ||
|
||
warning: skipping const checks | ||
| | ||
help: skipping check that does not even have a feature gate | ||
--> $DIR/mutable_references_err.rs:16:8 | ||
--> $DIR/mutable_references_err.rs:18:8 | ||
| | ||
LL | x: &UnsafeCell::new(42), | ||
| ^^^^^^^^^^^^^^^^^^^^ | ||
help: skipping check that does not even have a feature gate | ||
--> $DIR/mutable_references_err.rs:25:27 | ||
--> $DIR/mutable_references_err.rs:27:27 | ||
| | ||
LL | const SNEAKY: &dyn Sync = &Synced { x: UnsafeCell::new(42) }; | ||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | ||
help: skipping check that does not even have a feature gate | ||
--> $DIR/mutable_references_err.rs:29:25 | ||
--> $DIR/mutable_references_err.rs:32:40 | ||
| | ||
LL | const SUBTLE: &mut i32 = unsafe { &mut FOO }; | ||
| ^^^ | ||
help: skipping check that does not even have a feature gate | ||
--> $DIR/mutable_references_err.rs:32:40 | ||
| | ||
LL | const SUBTLE: &mut i32 = unsafe { &mut FOO }; | ||
| ^^^ | ||
help: skipping check that does not even have a feature gate | ||
--> $DIR/mutable_references_err.rs:32:35 | ||
| | ||
LL | const SUBTLE: &mut i32 = unsafe { &mut FOO }; | ||
| ^^^^^^^^ | ||
help: skipping check that does not even have a feature gate | ||
--> $DIR/mutable_references_err.rs:35:25 | ||
| | ||
LL | const BLUNT: &mut i32 = &mut 42; | ||
| ^^^^^^^ | ||
help: skipping check for `const_mut_refs` feature | ||
--> $DIR/mutable_references_err.rs:40:49 | ||
| | ||
LL | static mut MUT_TO_READONLY: &mut i32 = unsafe { &mut *(&READONLY as *const _ as *mut _) }; | ||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | ||
help: skipping check for `const_mut_refs` feature | ||
--> $DIR/mutable_references_err.rs:40:49 | ||
| | ||
LL | static mut MUT_TO_READONLY: &mut i32 = unsafe { &mut *(&READONLY as *const _ as *mut _) }; | ||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | ||
help: skipping check that does not even have a feature gate | ||
--> $DIR/mutable_references_err.rs:40:49 | ||
| | ||
LL | static mut MUT_TO_READONLY: &mut i32 = unsafe { &mut *(&READONLY as *const _ as *mut _) }; | ||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | ||
help: skipping check that does not even have a feature gate | ||
--> $DIR/mutable_references_err.rs:47:44 | ||
| | ||
LL | const POINTS_TO_MUTABLE1: &i32 = unsafe { &MUTABLE }; | ||
| ^^^^^^^ | ||
help: skipping check that does not even have a feature gate | ||
--> $DIR/mutable_references_err.rs:47:44 | ||
| | ||
LL | const POINTS_TO_MUTABLE1: &i32 = unsafe { &MUTABLE }; | ||
| ^^^^^^^ | ||
help: skipping check that does not even have a feature gate | ||
--> $DIR/mutable_references_err.rs:50:36 | ||
| | ||
LL | static mut MUTABLE_REF: &mut i32 = &mut 42; | ||
| ^^^^^^^ | ||
help: skipping check that does not even have a feature gate | ||
--> $DIR/mutable_references_err.rs:51:45 | ||
| | ||
LL | const POINTS_TO_MUTABLE2: &i32 = unsafe { &*MUTABLE_REF }; | ||
| ^^^^^^^^^^^ | ||
help: skipping check that does not even have a feature gate | ||
--> $DIR/mutable_references_err.rs:51:45 | ||
| | ||
LL | const POINTS_TO_MUTABLE2: &i32 = unsafe { &*MUTABLE_REF }; | ||
| ^^^^^^^^^^^ | ||
help: skipping check that does not even have a feature gate | ||
--> $DIR/mutable_references_err.rs:55:45 | ||
| | ||
LL | const POINTS_TO_MUTABLE_INNER: *const i32 = &mut 42 as *mut _ as *const _; | ||
| ^^^^^^^ | ||
help: skipping check that does not even have a feature gate | ||
--> $DIR/mutable_references_err.rs:65:51 | ||
| | ||
LL | const RAW_SYNC: SyncPtr<AtomicI32> = SyncPtr { x: &AtomicI32::new(42) }; | ||
| ^^^^^^^^^^^^^^^^^^^ | ||
help: skipping check that does not even have a feature gate | ||
--> $DIR/mutable_references_err.rs:67:50 | ||
| | ||
LL | const RAW_MUT_CAST: SyncPtr<i32> = SyncPtr { x : &mut 42 as *mut _ as *const _ }; | ||
| ^^^^^^^ | ||
help: skipping check that does not even have a feature gate | ||
--> $DIR/mutable_references_err.rs:69:51 | ||
| | ||
LL | const RAW_MUT_COERCE: SyncPtr<i32> = SyncPtr { x: &mut 0 }; | ||
| ^^^^^^ | ||
|
||
error: aborting due to 3 previous errors; 1 warning emitted | ||
error: aborting due to 11 previous errors; 1 warning emitted | ||
|
||
For more information about this error, try `rustc --explain E0080`. |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,8 +1,9 @@ | ||
// compile-flags: -Zunleash-the-miri-inside-of-you | ||
// Similar to `raw-ptr-const.rs`, but with *mutable* data. *Must* be rejected. | ||
|
||
use std::cell::UnsafeCell; | ||
|
||
const MUTABLE_BEHIND_RAW: *mut i32 = &UnsafeCell::new(42) as *const _ as *mut _; | ||
//~^ ERROR: unsupported untyped pointer in constant | ||
//~^ ERROR: mutable pointer in final value | ||
|
||
fn main() {} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,82 @@ | ||
error: encountered mutable pointer in final value of static | ||
--> $DIR/static-no-inner-mut.rs:9:1 | ||
| | ||
LL | static REF: &AtomicI32 = &AtomicI32::new(42); | ||
| ^^^^^^^^^^^^^^^^^^^^^^ | ||
|
||
error: encountered mutable pointer in final value of static | ||
--> $DIR/static-no-inner-mut.rs:10:1 | ||
| | ||
LL | static REFMUT: &mut i32 = &mut 0; | ||
| ^^^^^^^^^^^^^^^^^^^^^^^ | ||
|
||
error: encountered mutable pointer in final value of static | ||
--> $DIR/static-no-inner-mut.rs:13:1 | ||
| | ||
LL | static REF2: &AtomicI32 = {let x = AtomicI32::new(42); &{x}}; | ||
| ^^^^^^^^^^^^^^^^^^^^^^^ | ||
|
||
error: encountered mutable pointer in final value of static | ||
--> $DIR/static-no-inner-mut.rs:14:1 | ||
| | ||
LL | static REFMUT2: &mut i32 = {let mut x = 0; &mut {x}}; | ||
| ^^^^^^^^^^^^^^^^^^^^^^^^ | ||
|
||
error: encountered mutable pointer in final value of static | ||
--> $DIR/static-no-inner-mut.rs:29:1 | ||
| | ||
LL | static RAW_SYNC: SyncPtr<AtomicI32> = SyncPtr { x: &AtomicI32::new(42) }; | ||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | ||
|
||
error: encountered mutable pointer in final value of static | ||
--> $DIR/static-no-inner-mut.rs:31:1 | ||
| | ||
LL | static RAW_MUT_CAST: SyncPtr<i32> = SyncPtr { x : &mut 42 as *mut _ as *const _ }; | ||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | ||
|
||
error: encountered mutable pointer in final value of static | ||
--> $DIR/static-no-inner-mut.rs:33:1 | ||
| | ||
LL | static RAW_MUT_COERCE: SyncPtr<i32> = SyncPtr { x: &mut 0 }; | ||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | ||
|
||
warning: skipping const checks | ||
| | ||
help: skipping check that does not even have a feature gate | ||
--> $DIR/static-no-inner-mut.rs:9:26 | ||
| | ||
LL | static REF: &AtomicI32 = &AtomicI32::new(42); | ||
| ^^^^^^^^^^^^^^^^^^^ | ||
help: skipping check that does not even have a feature gate | ||
--> $DIR/static-no-inner-mut.rs:10:27 | ||
| | ||
LL | static REFMUT: &mut i32 = &mut 0; | ||
| ^^^^^^ | ||
help: skipping check that does not even have a feature gate | ||
--> $DIR/static-no-inner-mut.rs:13:56 | ||
| | ||
LL | static REF2: &AtomicI32 = {let x = AtomicI32::new(42); &{x}}; | ||
| ^^^^ | ||
help: skipping check that does not even have a feature gate | ||
--> $DIR/static-no-inner-mut.rs:14:44 | ||
| | ||
LL | static REFMUT2: &mut i32 = {let mut x = 0; &mut {x}}; | ||
| ^^^^^^^^ | ||
help: skipping check that does not even have a feature gate | ||
--> $DIR/static-no-inner-mut.rs:29:52 | ||
| | ||
LL | static RAW_SYNC: SyncPtr<AtomicI32> = SyncPtr { x: &AtomicI32::new(42) }; | ||
| ^^^^^^^^^^^^^^^^^^^ | ||
help: skipping check that does not even have a feature gate | ||
--> $DIR/static-no-inner-mut.rs:31:51 | ||
| | ||
LL | static RAW_MUT_CAST: SyncPtr<i32> = SyncPtr { x : &mut 42 as *mut _ as *const _ }; | ||
| ^^^^^^^ | ||
help: skipping check that does not even have a feature gate | ||
--> $DIR/static-no-inner-mut.rs:33:52 | ||
| | ||
LL | static RAW_MUT_COERCE: SyncPtr<i32> = SyncPtr { x: &mut 0 }; | ||
| ^^^^^^ | ||
|
||
error: aborting due to 7 previous errors; 1 warning emitted | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,82 @@ | ||
error: encountered mutable pointer in final value of static | ||
--> $DIR/static-no-inner-mut.rs:9:1 | ||
| | ||
LL | static REF: &AtomicI32 = &AtomicI32::new(42); | ||
| ^^^^^^^^^^^^^^^^^^^^^^ | ||
|
||
error: encountered mutable pointer in final value of static | ||
--> $DIR/static-no-inner-mut.rs:10:1 | ||
| | ||
LL | static REFMUT: &mut i32 = &mut 0; | ||
| ^^^^^^^^^^^^^^^^^^^^^^^ | ||
|
||
error: encountered mutable pointer in final value of static | ||
--> $DIR/static-no-inner-mut.rs:13:1 | ||
| | ||
LL | static REF2: &AtomicI32 = {let x = AtomicI32::new(42); &{x}}; | ||
| ^^^^^^^^^^^^^^^^^^^^^^^ | ||
|
||
error: encountered mutable pointer in final value of static | ||
--> $DIR/static-no-inner-mut.rs:14:1 | ||
| | ||
LL | static REFMUT2: &mut i32 = {let mut x = 0; &mut {x}}; | ||
| ^^^^^^^^^^^^^^^^^^^^^^^^ | ||
|
||
error: encountered mutable pointer in final value of static | ||
--> $DIR/static-no-inner-mut.rs:29:1 | ||
| | ||
LL | static RAW_SYNC: SyncPtr<AtomicI32> = SyncPtr { x: &AtomicI32::new(42) }; | ||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | ||
|
||
error: encountered mutable pointer in final value of static | ||
--> $DIR/static-no-inner-mut.rs:31:1 | ||
| | ||
LL | static RAW_MUT_CAST: SyncPtr<i32> = SyncPtr { x : &mut 42 as *mut _ as *const _ }; | ||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | ||
|
||
error: encountered mutable pointer in final value of static | ||
--> $DIR/static-no-inner-mut.rs:33:1 | ||
| | ||
LL | static RAW_MUT_COERCE: SyncPtr<i32> = SyncPtr { x: &mut 0 }; | ||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | ||
|
||
warning: skipping const checks | ||
| | ||
help: skipping check that does not even have a feature gate | ||
--> $DIR/static-no-inner-mut.rs:9:26 | ||
| | ||
LL | static REF: &AtomicI32 = &AtomicI32::new(42); | ||
| ^^^^^^^^^^^^^^^^^^^ | ||
help: skipping check that does not even have a feature gate | ||
--> $DIR/static-no-inner-mut.rs:10:27 | ||
| | ||
LL | static REFMUT: &mut i32 = &mut 0; | ||
| ^^^^^^ | ||
help: skipping check that does not even have a feature gate | ||
--> $DIR/static-no-inner-mut.rs:13:56 | ||
| | ||
LL | static REF2: &AtomicI32 = {let x = AtomicI32::new(42); &{x}}; | ||
| ^^^^ | ||
help: skipping check that does not even have a feature gate | ||
--> $DIR/static-no-inner-mut.rs:14:44 | ||
| | ||
LL | static REFMUT2: &mut i32 = {let mut x = 0; &mut {x}}; | ||
| ^^^^^^^^ | ||
help: skipping check that does not even have a feature gate | ||
--> $DIR/static-no-inner-mut.rs:29:52 | ||
| | ||
LL | static RAW_SYNC: SyncPtr<AtomicI32> = SyncPtr { x: &AtomicI32::new(42) }; | ||
| ^^^^^^^^^^^^^^^^^^^ | ||
help: skipping check that does not even have a feature gate | ||
--> $DIR/static-no-inner-mut.rs:31:51 | ||
| | ||
LL | static RAW_MUT_CAST: SyncPtr<i32> = SyncPtr { x : &mut 42 as *mut _ as *const _ }; | ||
| ^^^^^^^ | ||
help: skipping check that does not even have a feature gate | ||
--> $DIR/static-no-inner-mut.rs:33:52 | ||
| | ||
LL | static RAW_MUT_COERCE: SyncPtr<i32> = SyncPtr { x: &mut 0 }; | ||
| ^^^^^^ | ||
|
||
error: aborting due to 7 previous errors; 1 warning emitted | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,36 @@ | ||
// stderr-per-bitwidth | ||
// compile-flags: -Zunleash-the-miri-inside-of-you | ||
#![feature(const_refs_to_cell, const_mut_refs)] | ||
// All "inner" allocations that come with a `static` are interned immutably. This means it is | ||
// crucial that we do not accept any form of (interior) mutability there. | ||
|
||
use std::sync::atomic::*; | ||
|
||
static REF: &AtomicI32 = &AtomicI32::new(42); //~ERROR mutable pointer in final value | ||
static REFMUT: &mut i32 = &mut 0; //~ERROR mutable pointer in final value | ||
|
||
// Different way of writing this that avoids promotion. | ||
static REF2: &AtomicI32 = {let x = AtomicI32::new(42); &{x}}; //~ERROR mutable pointer in final value | ||
static REFMUT2: &mut i32 = {let mut x = 0; &mut {x}}; //~ERROR mutable pointer in final value | ||
|
||
// This one is obvious, since it is non-Sync. (It also suppresses the other errors, so it is | ||
// commented out.) | ||
// static RAW: *const AtomicI32 = &AtomicI32::new(42); | ||
|
||
struct SyncPtr<T> { x : *const T } | ||
unsafe impl<T> Sync for SyncPtr<T> {} | ||
|
||
// All of these pass the lifetime checks because of the "tail expression" / "outer scope" rule. | ||
// (This relies on `SyncPtr` being a curly brace struct.) | ||
// Then they get interned immutably, which is not great. | ||
// `mut_ref_in_final.rs` and `std/cell.rs` ensure that we don't accept this even with the feature | ||
// fate, but for unleashed Miri there's not really any way we can reject them: it's just | ||
// non-dangling raw pointers. | ||
static RAW_SYNC: SyncPtr<AtomicI32> = SyncPtr { x: &AtomicI32::new(42) }; | ||
//~^ ERROR mutable pointer in final value | ||
static RAW_MUT_CAST: SyncPtr<i32> = SyncPtr { x : &mut 42 as *mut _ as *const _ }; | ||
//~^ ERROR mutable pointer in final value | ||
static RAW_MUT_COERCE: SyncPtr<i32> = SyncPtr { x: &mut 0 }; | ||
//~^ ERROR mutable pointer in final value | ||
|
||
fn main() {} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,8 +1,8 @@ | ||
// check-pass | ||
|
||
// This is a regression test for a `span_delayed_bug` during interning when a constant | ||
// evaluates to a (non-dangling) raw pointer. For now this errors; potentially it | ||
// could also be allowed. | ||
// evaluates to a (non-dangling) raw pointer. | ||
|
||
const CONST_RAW: *const Vec<i32> = &Vec::new() as *const _; | ||
//~^ ERROR unsupported untyped pointer in constant | ||
|
||
fn main() {} |
This file was deleted.
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
#![feature(const_refs_to_cell)] | ||
|
||
use std::cell::*; | ||
|
||
struct SyncPtr<T> { x : *const T } | ||
unsafe impl<T> Sync for SyncPtr<T> {} | ||
|
||
// These pass the lifetime checks because of the "tail expression" / "outer scope" rule. | ||
// (This relies on `SyncPtr` being a curly brace struct.) | ||
// However, we intern the inner memory as read-only. | ||
// The resulting constant would pass all validation checks, so it is crucial that this gets rejected | ||
// by static const checks! | ||
static RAW_SYNC_S: SyncPtr<Cell<i32>> = SyncPtr { x: &Cell::new(42) }; | ||
//~^ ERROR: cannot refer to interior mutable data | ||
const RAW_SYNC_C: SyncPtr<Cell<i32>> = SyncPtr { x: &Cell::new(42) }; | ||
//~^ ERROR: cannot refer to interior mutable data | ||
|
||
fn main() {} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
error[E0492]: statics cannot refer to interior mutable data | ||
--> $DIR/refs-to-cell-in-final.rs:13:54 | ||
| | ||
LL | static RAW_SYNC_S: SyncPtr<Cell<i32>> = SyncPtr { x: &Cell::new(42) }; | ||
| ^^^^^^^^^^^^^^ this borrow of an interior mutable value may end up in the final value | ||
| | ||
= help: to fix this, the value can be extracted to a separate `static` item and then referenced | ||
|
||
error[E0492]: constants cannot refer to interior mutable data | ||
--> $DIR/refs-to-cell-in-final.rs:15:53 | ||
| | ||
LL | const RAW_SYNC_C: SyncPtr<Cell<i32>> = SyncPtr { x: &Cell::new(42) }; | ||
| ^^^^^^^^^^^^^^ this borrow of an interior mutable value may end up in the final value | ||
|
||
error: aborting due to 2 previous errors | ||
|
||
For more information about this error, try `rustc --explain E0492`. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@oli-obk the
is_static
parameter here seems redundant, I couldn't quite figure out why we have it?Uh oh!
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
😆 just to avoid a second
is_static
invocation, which is pretty useless as it's only required in the diagnostics path