Skip to content

Delay interning errors to after validation #122684

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

Merged
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
31 changes: 28 additions & 3 deletions compiler/rustc_const_eval/src/const_eval/eval_queries.rs
Original file line number Diff line number Diff line change
@@ -10,20 +10,21 @@ use rustc_middle::traits::Reveal;
use rustc_middle::ty::layout::LayoutOf;
use rustc_middle::ty::print::with_no_trimmed_paths;
use rustc_middle::ty::{self, Ty, TyCtxt};
use rustc_session::lint;
use rustc_span::def_id::LocalDefId;
use rustc_span::Span;
use rustc_target::abi::{self, Abi};

use super::{CanAccessMutGlobal, CompileTimeEvalContext, CompileTimeInterpreter};
use crate::const_eval::CheckAlignment;
use crate::errors;
use crate::errors::ConstEvalError;
use crate::interpret::eval_nullary_intrinsic;
use crate::errors::{self, DanglingPtrInFinal};
use crate::interpret::{
create_static_alloc, intern_const_alloc_recursive, CtfeValidationMode, GlobalId, Immediate,
InternKind, InterpCx, InterpError, InterpResult, MPlaceTy, MemoryKind, OpTy, RefTracking,
StackPopCleanup,
};
use crate::interpret::{eval_nullary_intrinsic, InternResult};
use crate::CTRL_C_RECEIVED;

// Returns a pointer to where the result lives
@@ -89,11 +90,35 @@ fn eval_body_using_ecx<'mir, 'tcx, R: InterpretationResult<'tcx>>(
}

// Intern the result
intern_const_alloc_recursive(ecx, intern_kind, &ret)?;
let intern_result = intern_const_alloc_recursive(ecx, intern_kind, &ret);

// Since evaluation had no errors, validate the resulting constant.
const_validate_mplace(&ecx, &ret, cid)?;

// Only report this after validation, as validaiton produces much better diagnostics.
// FIXME: ensure validation always reports this and stop making interning care about it.

match intern_result {
Ok(()) => {}
Err(InternResult::FoundDanglingPointer) => {
return Err(ecx
.tcx
.dcx()
.emit_err(DanglingPtrInFinal { span: ecx.tcx.span, kind: intern_kind })
.into());
}
Err(InternResult::FoundBadMutablePointer) => {
// only report mutable pointers if there were no dangling pointers
let err_diag = errors::MutablePtrInFinal { span: ecx.tcx.span, kind: intern_kind };
ecx.tcx.emit_node_span_lint(
lint::builtin::CONST_EVAL_MUTABLE_PTR_IN_FINAL_VALUE,
ecx.best_lint_scope(),
err_diag.span,
err_diag,
)
}
}

Ok(R::make_result(ret, ecx))
}

41 changes: 21 additions & 20 deletions compiler/rustc_const_eval/src/interpret/intern.rs
Original file line number Diff line number Diff line change
@@ -16,19 +16,17 @@
use hir::def::DefKind;
use rustc_ast::Mutability;
use rustc_data_structures::fx::{FxHashSet, FxIndexMap};
use rustc_errors::ErrorGuaranteed;
use rustc_hir as hir;
use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrs;
use rustc_middle::mir::interpret::{ConstAllocation, CtfeProvenance, InterpResult};
use rustc_middle::query::TyCtxtAt;
use rustc_middle::ty::layout::TyAndLayout;
use rustc_session::lint;
use rustc_span::def_id::LocalDefId;
use rustc_span::sym;

use super::{AllocId, Allocation, InterpCx, MPlaceTy, Machine, MemoryKind, PlaceTy};
use crate::const_eval;
use crate::errors::{DanglingPtrInFinal, MutablePtrInFinal, NestedStaticInThreadLocal};
use crate::errors::NestedStaticInThreadLocal;

pub trait CompileTimeMachine<'mir, 'tcx: 'mir, T> = Machine<
'mir,
@@ -134,6 +132,12 @@ pub enum InternKind {
Promoted,
}

#[derive(Debug)]
pub enum InternResult {
FoundBadMutablePointer,
FoundDanglingPointer,
}

/// Intern `ret` and everything it references.
///
/// This *cannot raise an interpreter error*. Doing so is left to validation, which
@@ -149,7 +153,7 @@ pub fn intern_const_alloc_recursive<
ecx: &mut InterpCx<'mir, 'tcx, M>,
intern_kind: InternKind,
ret: &MPlaceTy<'tcx>,
) -> Result<(), ErrorGuaranteed> {
) -> Result<(), InternResult> {
// We are interning recursively, and for mutability we are distinguishing the "root" allocation
// that we are starting in, and all other allocations that we are encountering recursively.
let (base_mutability, inner_mutability, is_static) = match intern_kind {
@@ -201,7 +205,7 @@ pub fn intern_const_alloc_recursive<
// Whether we encountered a bad mutable pointer.
// We want to first report "dangling" and then "mutable", so we need to delay reporting these
// errors.
let mut found_bad_mutable_pointer = false;
let mut result = Ok(());

// Keep interning as long as there are things to intern.
// We show errors if there are dangling pointers, or mutable pointers in immutable contexts
@@ -251,7 +255,10 @@ pub fn intern_const_alloc_recursive<
// on the promotion analysis not screwing up to ensure that it is sound to intern
// promoteds as immutable.
trace!("found bad mutable pointer");
found_bad_mutable_pointer = true;
// Prefer dangling pointer errors over mutable pointer errors
if result.is_ok() {
result = Err(InternResult::FoundBadMutablePointer);
}
}
if ecx.tcx.try_get_global_alloc(alloc_id).is_some() {
// Already interned.
@@ -269,21 +276,15 @@ pub fn intern_const_alloc_recursive<
// pointers before deciding which allocations can be made immutable; but for now we are
// okay with losing some potential for immutability here. This can anyway only affect
// `static mut`.
todo.extend(intern_shallow(ecx, alloc_id, inner_mutability).map_err(|()| {
ecx.tcx.dcx().emit_err(DanglingPtrInFinal { span: ecx.tcx.span, kind: intern_kind })
})?);
}
if found_bad_mutable_pointer {
let err_diag = MutablePtrInFinal { span: ecx.tcx.span, kind: intern_kind };
ecx.tcx.emit_node_span_lint(
lint::builtin::CONST_EVAL_MUTABLE_PTR_IN_FINAL_VALUE,
ecx.best_lint_scope(),
err_diag.span,
err_diag,
)
match intern_shallow(ecx, alloc_id, inner_mutability) {
Ok(nested) => todo.extend(nested),
Err(()) => {
ecx.tcx.dcx().delayed_bug("found dangling pointer during const interning");
result = Err(InternResult::FoundDanglingPointer);
}
}
}

Ok(())
result
}

/// Intern `ret`. This function assumes that `ret` references no other allocation.
1 change: 1 addition & 0 deletions compiler/rustc_const_eval/src/interpret/mod.rs
Original file line number Diff line number Diff line change
@@ -23,6 +23,7 @@ pub use rustc_middle::mir::interpret::*; // have all the `interpret` symbols in
pub use self::eval_context::{format_interp_error, Frame, FrameInfo, InterpCx, StackPopCleanup};
pub use self::intern::{
intern_const_alloc_for_constprop, intern_const_alloc_recursive, HasStaticRootDefId, InternKind,
InternResult,
};
pub use self::machine::{compile_time_machine, AllocMap, Machine, MayLeak, StackPopJump};
pub use self::memory::{AllocKind, AllocRef, AllocRefMut, FnVal, Memory, MemoryKind};
143 changes: 79 additions & 64 deletions compiler/rustc_const_eval/src/interpret/validity.rs
Original file line number Diff line number Diff line change
@@ -449,67 +449,41 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValidityVisitor<'rt, 'mir, '
// `!` 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()) {
let mut skip_recursive_check = false;
// Let's see what kind of memory this points to.
// `unwrap` since dangling pointers have already been handled.
let alloc_kind = self.ecx.tcx.try_get_global_alloc(alloc_id).unwrap();
let alloc_actual_mutbl = match alloc_kind {
GlobalAlloc::Static(did) => {
// 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));
// Mode-specific checks
match self.ctfe_mode {
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 (potentially through a promoted).
// This could miss some UB, but that's fine.
skip_recursive_check = true;
}
Some(CtfeValidationMode::Const { .. }) => {
// We can't recursively validate `extern static`, so we better reject them.
if self.ecx.tcx.is_foreign_item(did) {
throw_validation_failure!(self.path, ConstRefToExtern);
}
}
None => {}
let alloc_actual_mutbl = mutability(self.ecx, alloc_id);
if let GlobalAlloc::Static(did) = self.ecx.tcx.global_alloc(alloc_id) {
let DefKind::Static { nested, .. } = self.ecx.tcx.def_kind(did) else { bug!() };
// 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));
// Mode-specific checks
match self.ctfe_mode {
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 (potentially through a promoted).
// This could miss some UB, but that's fine.
// We still walk nested allocations, as they are fundamentally part of this validation run.
// This means we will also recurse into nested statics of *other*
// statics, even though we do not recurse into other statics directly.
// That's somewhat inconsistent but harmless.
skip_recursive_check = !nested;
}
// Return alloc mutability. For "root" statics we look at the type to account for interior
// mutability; for nested statics we have no type and directly use the annotated mutability.
let DefKind::Static { mutability, nested } = self.ecx.tcx.def_kind(did)
else {
bug!()
};
match (mutability, nested) {
(Mutability::Mut, _) => Mutability::Mut,
(Mutability::Not, true) => Mutability::Not,
(Mutability::Not, false)
if !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()) =>
{
Mutability::Mut
Some(CtfeValidationMode::Const { .. }) => {
// We can't recursively validate `extern static`, so we better reject them.
if self.ecx.tcx.is_foreign_item(did) {
throw_validation_failure!(self.path, ConstRefToExtern);
}
(Mutability::Not, false) => Mutability::Not,
}
None => {}
}
GlobalAlloc::Memory(alloc) => alloc.inner().mutability,
GlobalAlloc::Function(..) | GlobalAlloc::VTable(..) => {
// These are immutable, we better don't allow mutable pointers here.
Mutability::Not
}
};
}

// Mutability check.
// If this allocation has size zero, there is no actual mutability here.
let (size, _align, _alloc_kind) = self.ecx.get_alloc_info(alloc_id);
@@ -708,17 +682,58 @@ 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()) {
let mutability = match self.ecx.tcx.global_alloc(alloc_id) {
GlobalAlloc::Static(_) => {
self.ecx.memory.alloc_map.get(alloc_id).unwrap().1.mutability
return mutability(self.ecx, alloc_id).is_mut();
}
}
false
}
}

/// Returns whether the allocation is mutable, and whether it's actually a static.
/// For "root" statics we look at the type to account for interior
/// mutability; for nested statics we have no type and directly use the annotated mutability.
fn mutability<'mir, 'tcx: 'mir>(
ecx: &InterpCx<'mir, 'tcx, impl Machine<'mir, 'tcx>>,
alloc_id: AllocId,
) -> Mutability {
// Let's see what kind of memory this points to.
// We're not using `try_global_alloc` since dangling pointers have already been handled.
match ecx.tcx.global_alloc(alloc_id) {
GlobalAlloc::Static(did) => {
let DefKind::Static { mutability, nested } = ecx.tcx.def_kind(did) else { bug!() };
if nested {
assert!(
ecx.memory.alloc_map.get(alloc_id).is_none(),
"allocations of nested statics are already interned: {alloc_id:?}, {did:?}"
);
// Nested statics in a `static` are never interior mutable,
// so just use the declared mutability.
mutability
} else {
let mutability = match mutability {
Mutability::Not
if !ecx
.tcx
.type_of(did)
.no_bound_vars()
.expect("statics should not have generic parameters")
.is_freeze(*ecx.tcx, ty::ParamEnv::reveal_all()) =>
{
Mutability::Mut
}
GlobalAlloc::Memory(alloc) => alloc.inner().mutability,
_ => span_bug!(self.ecx.tcx.span, "not a memory allocation"),
_ => mutability,
};
return mutability == Mutability::Mut;
if let Some((_, alloc)) = ecx.memory.alloc_map.get(alloc_id) {
assert_eq!(alloc.mutability, mutability);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can this assertion be moved outside the if nested { ... } else { ... }?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There will never be an entry for nested statics. They have already been interned. I'll assert that there is no such entry.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah I had not even noticed that this specifically checks the alloc_map. Why that? Is it possible to use get_alloc_mutability instead and do this sanity check for all statics, nested or otherwise?

The only thing that has not been interned here is the root alloc of a static, right?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We can't use that as it actually fetches the allocation, and that will cause cycle errors for recursive statics

static S: *const u8 = &S as *const *const u8 as *const u8;

has a different AllocId for &S than it has for the root allocation. The root allocation's AllocId will never be leaked, but we still need it for evaluating the static itself. While this case can be detected, mutually recursive statics are impossible to detect locally.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am confused -- I thought we use the same AllocId for the return place as for the static?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm right. No idea where the cycle errors are coming from then. I just tested it and they still occur.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If you called get_alloc_raw or something like that, that's still querying the static so would lead to a cycle if it is the current static.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah this is an ICE fix as well it seems, nice. :D

}
mutability
}
}
false
GlobalAlloc::Memory(alloc) => alloc.inner().mutability,
GlobalAlloc::Function(..) | GlobalAlloc::VTable(..) => {
// These are immutable, we better don't allow mutable pointers here.
Mutability::Not
}
}
}

17 changes: 0 additions & 17 deletions tests/crashes/122548.rs

This file was deleted.

Original file line number Diff line number Diff line change
@@ -2,10 +2,15 @@
#![feature(const_heap)]
#![feature(const_mut_refs)]

// Strip out raw byte dumps to make comparison platform-independent:
//@ normalize-stderr-test "(the raw bytes of the constant) \(size: [0-9]*, align: [0-9]*\)" -> "$1 (size: $$SIZE, align: $$ALIGN)"
//@ normalize-stderr-test "([0-9a-f][0-9a-f] |╾─*A(LLOC)?[0-9]+(\+[a-z0-9]+)?(<imm>)?─*╼ )+ *│.*" -> "HEX_DUMP"
//@ normalize-stderr-test "HEX_DUMP\s*\n\s*HEX_DUMP" -> "HEX_DUMP"

use std::intrinsics;

const _X: &'static u8 = unsafe {
//~^ error: dangling pointer in final value of constant
//~^ error: it is undefined behavior to use this value
let ptr = intrinsics::const_allocate(4, 4);
intrinsics::const_deallocate(ptr, 4, 4);
&*ptr
15 changes: 10 additions & 5 deletions tests/ui/consts/const-eval/heap/dealloc_intrinsic_dangling.stderr
Original file line number Diff line number Diff line change
@@ -1,14 +1,19 @@
error: encountered dangling pointer in final value of constant
--> $DIR/dealloc_intrinsic_dangling.rs:7:1
error[E0080]: it is undefined behavior to use this value
--> $DIR/dealloc_intrinsic_dangling.rs:12:1
|
LL | const _X: &'static u8 = unsafe {
| ^^^^^^^^^^^^^^^^^^^^^
| ^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered a dangling reference (use-after-free)
|
= 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: $SIZE, align: $ALIGN) {
HEX_DUMP
}

error[E0080]: evaluation of constant value failed
--> $DIR/dealloc_intrinsic_dangling.rs:18:5
--> $DIR/dealloc_intrinsic_dangling.rs:23:5
|
LL | *reference
| ^^^^^^^^^^ memory access failed: ALLOC0 has been freed, so this pointer is dangling
| ^^^^^^^^^^ memory access failed: ALLOC1 has been freed, so this pointer is dangling

error: aborting due to 2 previous errors

Original file line number Diff line number Diff line change
@@ -33,8 +33,8 @@ const fn helper_dangling() -> Option<&'static mut i32> { unsafe {
// Undefined behaviour (dangling pointer), who doesn't love tests like this.
Some(&mut *(&mut 42 as *mut i32))
} }
const DANGLING: Option<&mut i32> = helper_dangling(); //~ ERROR encountered dangling pointer
static DANGLING_STATIC: Option<&mut i32> = helper_dangling(); //~ ERROR encountered dangling pointer
const DANGLING: Option<&mut i32> = helper_dangling(); //~ ERROR it is undefined behavior to use this value
static DANGLING_STATIC: Option<&mut i32> = helper_dangling(); //~ ERROR it is undefined behavior to use this value

// These are fine! Just statics pointing to mutable statics, nothing fundamentally wrong with this.
static MUT_STATIC: Option<&mut i32> = helper();
Original file line number Diff line number Diff line change
@@ -31,17 +31,27 @@ LL | static INT2PTR_STATIC: Option<&mut i32> = helper_int2ptr();
HEX_DUMP
}

error: encountered dangling pointer in final value of constant
error[E0080]: it is undefined behavior to use this value
--> $DIR/mut_ref_in_final_dynamic_check.rs:36:1
|
LL | const DANGLING: Option<&mut i32> = helper_dangling();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .<enum-variant(Some)>.0: encountered a dangling reference (use-after-free)
|
= 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: $SIZE, align: $ALIGN) {
HEX_DUMP
}

error: encountered dangling pointer in final value of static
error[E0080]: it is undefined behavior to use this value
--> $DIR/mut_ref_in_final_dynamic_check.rs:37:1
|
LL | static DANGLING_STATIC: Option<&mut i32> = helper_dangling();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .<enum-variant(Some)>.0: encountered a dangling reference (use-after-free)
|
= 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: $SIZE, align: $ALIGN) {
HEX_DUMP
}

error: aborting due to 5 previous errors

6 changes: 5 additions & 1 deletion tests/ui/consts/dangling-alloc-id-ice.rs
Original file line number Diff line number Diff line change
@@ -1,12 +1,16 @@
// https://github.com/rust-lang/rust/issues/55223
// Strip out raw byte dumps to make comparison platform-independent:
//@ normalize-stderr-test "(the raw bytes of the constant) \(size: [0-9]*, align: [0-9]*\)" -> "$1 (size: $$SIZE, align: $$ALIGN)"
//@ normalize-stderr-test "([0-9a-f][0-9a-f] |╾─*A(LLOC)?[0-9]+(\+[a-z0-9]+)?(<imm>)?─*╼ )+ *│.*" -> "HEX_DUMP"
//@ normalize-stderr-test "HEX_DUMP\s*\n\s*HEX_DUMP" -> "HEX_DUMP"

union Foo<'a> {
y: &'a (),
long_live_the_unit: &'static (),
}

const FOO: &() = {
//~^ ERROR encountered dangling pointer in final value of constant
//~^ ERROR it is undefined behavior to use this value
let y = ();
unsafe { Foo { y: &y }.long_live_the_unit }
};
12 changes: 9 additions & 3 deletions tests/ui/consts/dangling-alloc-id-ice.stderr
Original file line number Diff line number Diff line change
@@ -1,8 +1,14 @@
error: encountered dangling pointer in final value of constant
--> $DIR/dangling-alloc-id-ice.rs:8:1
error[E0080]: it is undefined behavior to use this value
--> $DIR/dangling-alloc-id-ice.rs:12:1
|
LL | const FOO: &() = {
| ^^^^^^^^^^^^^^
| ^^^^^^^^^^^^^^ constructing invalid value: encountered a dangling reference (use-after-free)
|
= 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: $SIZE, align: $ALIGN) {
HEX_DUMP
}

error: aborting due to 1 previous error

For more information about this error, try `rustc --explain E0080`.
27 changes: 24 additions & 3 deletions tests/ui/consts/dangling_raw_ptr.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,29 @@
const FOO: *const u32 = { //~ ERROR encountered dangling pointer in final value of constant
const FOO: *const u32 = {
//~^ ERROR encountered dangling pointer in final value of constant
let x = 42;
&x
};

fn main() {
let x = FOO;
union Union {
ptr: *const u32,
}

const BAR: Union = {
//~^ ERROR encountered dangling pointer in final value of constant
let x = 42;
Union { ptr: &x }
};

const BAZ: Union = {
//~^ ERROR encountered dangling pointer in final value of constant
let x = 42_u32;
Union { ptr: &(&x as *const u32) as *const *const u32 as _ }
};

const FOOMP: *const u32 = {
//~^ ERROR encountered dangling pointer in final value of constant
let x = 42_u32;
&(&x as *const u32) as *const *const u32 as _
};

fn main() {}
20 changes: 19 additions & 1 deletion tests/ui/consts/dangling_raw_ptr.stderr
Original file line number Diff line number Diff line change
@@ -4,5 +4,23 @@ error: encountered dangling pointer in final value of constant
LL | const FOO: *const u32 = {
| ^^^^^^^^^^^^^^^^^^^^^

error: aborting due to 1 previous error
error: encountered dangling pointer in final value of constant
--> $DIR/dangling_raw_ptr.rs:11:1
|
LL | const BAR: Union = {
| ^^^^^^^^^^^^^^^^

error: encountered dangling pointer in final value of constant
--> $DIR/dangling_raw_ptr.rs:17:1
|
LL | const BAZ: Union = {
| ^^^^^^^^^^^^^^^^

error: encountered dangling pointer in final value of constant
--> $DIR/dangling_raw_ptr.rs:23:1
|
LL | const FOOMP: *const u32 = {
| ^^^^^^^^^^^^^^^^^^^^^^^

error: aborting due to 4 previous errors

13 changes: 4 additions & 9 deletions tests/ui/consts/miri_unleashed/mutable_references.rs
Original file line number Diff line number Diff line change
@@ -5,11 +5,9 @@
#![deny(const_eval_mutable_ptr_in_final_value)]
use std::cell::UnsafeCell;

// a test demonstrating what things we could allow with a smarter const qualification

// This requires walking nested statics.
static FOO: &&mut u32 = &&mut 42;
//~^ ERROR encountered mutable pointer in final value of static
//~| WARNING this was previously accepted by the compiler
//~^ ERROR it is undefined behavior to use this value

static BAR: &mut () = &mut ();
//~^ ERROR encountered mutable pointer in final value of static
@@ -26,13 +24,10 @@ struct Meh {
}
unsafe impl Sync for Meh {}
static MEH: Meh = Meh { x: &UnsafeCell::new(42) };
//~^ ERROR encountered mutable pointer in final value of static
//~| WARNING this was previously accepted by the compiler
//~^ ERROR it is undefined behavior to use this value

static OH_YES: &mut i32 = &mut 42;
//~^ ERROR encountered mutable pointer in final value of static
//~| WARNING this was previously accepted by the compiler
//~| ERROR it is undefined behavior to use this value
//~^ ERROR it is undefined behavior to use this value

fn main() {
unsafe {
112 changes: 31 additions & 81 deletions tests/ui/consts/miri_unleashed/mutable_references.stderr
Original file line number Diff line number Diff line change
@@ -1,55 +1,50 @@
error: encountered mutable pointer in final value of static
--> $DIR/mutable_references.rs:10:1
error[E0080]: it is undefined behavior to use this value
--> $DIR/mutable_references.rs:9:1
|
LL | static FOO: &&mut u32 = &&mut 42;
| ^^^^^^^^^^^^^^^^^^^^^
| ^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .<deref>: encountered mutable reference or box pointing to read-only memory
|
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
= note: for more information, see issue #122153 <https://github.com/rust-lang/rust/issues/122153>
note: the lint level is defined here
--> $DIR/mutable_references.rs:5:9
|
LL | #![deny(const_eval_mutable_ptr_in_final_value)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
= 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: $SIZE, align: $ALIGN) {
HEX_DUMP
}

error: encountered mutable pointer in final value of static
--> $DIR/mutable_references.rs:14:1
--> $DIR/mutable_references.rs:12:1
|
LL | static BAR: &mut () = &mut ();
| ^^^^^^^^^^^^^^^^^^^
|
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
= note: for more information, see issue #122153 <https://github.com/rust-lang/rust/issues/122153>
note: the lint level is defined here
--> $DIR/mutable_references.rs:5:9
|
LL | #![deny(const_eval_mutable_ptr_in_final_value)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

error: encountered mutable pointer in final value of static
--> $DIR/mutable_references.rs:20:1
--> $DIR/mutable_references.rs:18:1
|
LL | static BOO: &mut Foo<()> = &mut Foo(());
| ^^^^^^^^^^^^^^^^^^^^^^^^
|
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
= note: for more information, see issue #122153 <https://github.com/rust-lang/rust/issues/122153>

error: encountered mutable pointer in final value of static
--> $DIR/mutable_references.rs:28:1
error[E0080]: it is undefined behavior to use this value
--> $DIR/mutable_references.rs:26:1
|
LL | static MEH: Meh = Meh { x: &UnsafeCell::new(42) };
| ^^^^^^^^^^^^^^^
|
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
= note: for more information, see issue #122153 <https://github.com/rust-lang/rust/issues/122153>

error: encountered mutable pointer in final value of static
--> $DIR/mutable_references.rs:32:1
|
LL | static OH_YES: &mut i32 = &mut 42;
| ^^^^^^^^^^^^^^^^^^^^^^^
| ^^^^^^^^^^^^^^^ constructing invalid value at .x.<deref>: encountered `UnsafeCell` in read-only memory
|
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
= note: for more information, see issue #122153 <https://github.com/rust-lang/rust/issues/122153>
= 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: $SIZE, align: $ALIGN) {
HEX_DUMP
}

error[E0080]: it is undefined behavior to use this value
--> $DIR/mutable_references.rs:32:1
--> $DIR/mutable_references.rs:29:1
|
LL | static OH_YES: &mut i32 = &mut 42;
| ^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered mutable reference or box pointing to read-only memory
@@ -60,61 +55,46 @@ LL | static OH_YES: &mut i32 = &mut 42;
}

error[E0594]: cannot assign to `*OH_YES`, as `OH_YES` is an immutable static item
--> $DIR/mutable_references.rs:41:5
--> $DIR/mutable_references.rs:36:5
|
LL | *OH_YES = 99;
| ^^^^^^^^^^^^ cannot assign

warning: skipping const checks
|
help: skipping check that does not even have a feature gate
--> $DIR/mutable_references.rs:10:26
--> $DIR/mutable_references.rs:9:26
|
LL | static FOO: &&mut u32 = &&mut 42;
| ^^^^^^^
help: skipping check that does not even have a feature gate
--> $DIR/mutable_references.rs:14:23
--> $DIR/mutable_references.rs:12:23
|
LL | static BAR: &mut () = &mut ();
| ^^^^^^^
help: skipping check that does not even have a feature gate
--> $DIR/mutable_references.rs:20:28
--> $DIR/mutable_references.rs:18:28
|
LL | static BOO: &mut Foo<()> = &mut Foo(());
| ^^^^^^^^^^^^
help: skipping check that does not even have a feature gate
--> $DIR/mutable_references.rs:28:28
--> $DIR/mutable_references.rs:26:28
|
LL | static MEH: Meh = Meh { x: &UnsafeCell::new(42) };
| ^^^^^^^^^^^^^^^^^^^^
help: skipping check that does not even have a feature gate
--> $DIR/mutable_references.rs:32:27
--> $DIR/mutable_references.rs:29:27
|
LL | static OH_YES: &mut i32 = &mut 42;
| ^^^^^^^

error: aborting due to 7 previous errors; 1 warning emitted
error: aborting due to 6 previous errors; 1 warning emitted

Some errors have detailed explanations: E0080, E0594.
For more information about an error, try `rustc --explain E0080`.
Future incompatibility report: Future breakage diagnostic:
error: encountered mutable pointer in final value of static
--> $DIR/mutable_references.rs:10:1
|
LL | static FOO: &&mut u32 = &&mut 42;
| ^^^^^^^^^^^^^^^^^^^^^
|
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
= note: for more information, see issue #122153 <https://github.com/rust-lang/rust/issues/122153>
note: the lint level is defined here
--> $DIR/mutable_references.rs:5:9
|
LL | #![deny(const_eval_mutable_ptr_in_final_value)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

Future breakage diagnostic:
error: encountered mutable pointer in final value of static
--> $DIR/mutable_references.rs:14:1
--> $DIR/mutable_references.rs:12:1
|
LL | static BAR: &mut () = &mut ();
| ^^^^^^^^^^^^^^^^^^^
@@ -129,7 +109,7 @@ LL | #![deny(const_eval_mutable_ptr_in_final_value)]

Future breakage diagnostic:
error: encountered mutable pointer in final value of static
--> $DIR/mutable_references.rs:20:1
--> $DIR/mutable_references.rs:18:1
|
LL | static BOO: &mut Foo<()> = &mut Foo(());
| ^^^^^^^^^^^^^^^^^^^^^^^^
@@ -142,33 +122,3 @@ note: the lint level is defined here
LL | #![deny(const_eval_mutable_ptr_in_final_value)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

Future breakage diagnostic:
error: encountered mutable pointer in final value of static
--> $DIR/mutable_references.rs:28:1
|
LL | static MEH: Meh = Meh { x: &UnsafeCell::new(42) };
| ^^^^^^^^^^^^^^^
|
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
= note: for more information, see issue #122153 <https://github.com/rust-lang/rust/issues/122153>
note: the lint level is defined here
--> $DIR/mutable_references.rs:5:9
|
LL | #![deny(const_eval_mutable_ptr_in_final_value)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

Future breakage diagnostic:
error: encountered mutable pointer in final value of static
--> $DIR/mutable_references.rs:32:1
|
LL | static OH_YES: &mut i32 = &mut 42;
| ^^^^^^^^^^^^^^^^^^^^^^^
|
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
= note: for more information, see issue #122153 <https://github.com/rust-lang/rust/issues/122153>
note: the lint level is defined here
--> $DIR/mutable_references.rs:5:9
|
LL | #![deny(const_eval_mutable_ptr_in_final_value)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

12 changes: 3 additions & 9 deletions tests/ui/consts/miri_unleashed/mutable_references_err.rs
Original file line number Diff line number Diff line change
@@ -16,9 +16,7 @@ unsafe impl Sync for Meh {}
// the following will never be ok! no interior mut behind consts, because
// all allocs interned here will be marked immutable.
const MUH: Meh = Meh {
//~^ ERROR encountered mutable pointer in final value of constant
//~| WARNING this was previously accepted by the compiler
//~| ERROR: it is undefined behavior to use this value
//~^ ERROR it is undefined behavior to use this value
x: &UnsafeCell::new(42),
};

@@ -29,9 +27,7 @@ unsafe impl Sync for Synced {}

// Make sure we also catch this behind a type-erased `dyn Trait` reference.
const SNEAKY: &dyn Sync = &Synced { x: UnsafeCell::new(42) };
//~^ ERROR: mutable pointer in final value
//~| WARNING this was previously accepted by the compiler
//~| ERROR it is undefined behavior to use this value
//~^ ERROR: it is undefined behavior to use this value

// Make sure we also catch mutable references in values that shouldn't have them.
static mut FOO: i32 = 0;
@@ -40,9 +36,7 @@ const SUBTLE: &mut i32 = unsafe { &mut FOO };
//~| static

const BLUNT: &mut i32 = &mut 42;
//~^ ERROR: mutable pointer in final value
//~| WARNING this was previously accepted by the compiler
//~| ERROR it is undefined behavior to use this value
//~^ ERROR: it is undefined behavior to use this value

// Check for mutable references to read-only memory.
static READONLY: i32 = 0;
152 changes: 40 additions & 112 deletions tests/ui/consts/miri_unleashed/mutable_references_err.stderr

Large diffs are not rendered by default.

144 changes: 35 additions & 109 deletions tests/ui/consts/miri_unleashed/static-no-inner-mut.32bit.stderr
Original file line number Diff line number Diff line change
@@ -1,77 +1,63 @@
error: encountered mutable pointer in final value of static
error[E0080]: it is undefined behavior to use this value
--> $DIR/static-no-inner-mut.rs:9:1
|
LL | static REF: &AtomicI32 = &AtomicI32::new(42);
| ^^^^^^^^^^^^^^^^^^^^^^
|
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
= note: for more information, see issue #122153 <https://github.com/rust-lang/rust/issues/122153>
note: the lint level is defined here
--> $DIR/static-no-inner-mut.rs:6:9
|
LL | #![deny(const_eval_mutable_ptr_in_final_value)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

error: encountered mutable pointer in final value of static
--> $DIR/static-no-inner-mut.rs:13:1
| ^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .<deref>.v: encountered `UnsafeCell` in read-only memory
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The obvious reaction to this will be "so why is that memory read-only"...

|
LL | static REFMUT: &mut i32 = &mut 0;
| ^^^^^^^^^^^^^^^^^^^^^^^
|
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
= note: for more information, see issue #122153 <https://github.com/rust-lang/rust/issues/122153>
= 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[E0080]: it is undefined behavior to use this value
--> $DIR/static-no-inner-mut.rs:13:1
--> $DIR/static-no-inner-mut.rs:12:1
|
LL | static REFMUT: &mut i32 = &mut 0;
| ^^^^^^^^^^^^^^^^^^^^^^^ 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: 4, align: 4) {
ALLOC0╼ │ ╾──╼
ALLOC1╼ │ ╾──╼
}

error: encountered mutable pointer in final value of static
--> $DIR/static-no-inner-mut.rs:19:1
error[E0080]: it is undefined behavior to use this value
--> $DIR/static-no-inner-mut.rs:16:1
|
LL | static REF2: &AtomicI32 = {let x = AtomicI32::new(42); &{x}};
| ^^^^^^^^^^^^^^^^^^^^^^^
| ^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .<deref>.v: encountered `UnsafeCell` in read-only memory
|
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
= note: for more information, see issue #122153 <https://github.com/rust-lang/rust/issues/122153>

error: encountered mutable pointer in final value of static
--> $DIR/static-no-inner-mut.rs:23:1
|
LL | static REFMUT2: &mut i32 = {let mut x = 0; &mut {x}};
| ^^^^^^^^^^^^^^^^^^^^^^^^
|
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
= note: for more information, see issue #122153 <https://github.com/rust-lang/rust/issues/122153>
= 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) {
╾ALLOC2╼ │ ╾──╼
}

error[E0080]: it is undefined behavior to use this value
--> $DIR/static-no-inner-mut.rs:23:1
--> $DIR/static-no-inner-mut.rs:18:1
|
LL | static REFMUT2: &mut i32 = {let mut x = 0; &mut {x}};
| ^^^^^^^^^^^^^^^^^^^^^^^^ 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: 4, align: 4) {
ALLOC1╼ │ ╾──╼
ALLOC3╼ │ ╾──╼
}

error: encountered mutable pointer in final value of static
--> $DIR/static-no-inner-mut.rs:41:1
--> $DIR/static-no-inner-mut.rs:34:1
|
LL | static RAW_SYNC: SyncPtr<AtomicI32> = SyncPtr { x: &AtomicI32::new(42) };
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
= note: for more information, see issue #122153 <https://github.com/rust-lang/rust/issues/122153>
note: the lint level is defined here
--> $DIR/static-no-inner-mut.rs:6:9
|
LL | #![deny(const_eval_mutable_ptr_in_final_value)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

error: encountered mutable pointer in final value of static
--> $DIR/static-no-inner-mut.rs:45:1
--> $DIR/static-no-inner-mut.rs:38:1
|
LL | static RAW_MUT_CAST: SyncPtr<i32> = SyncPtr { x : &mut 42 as *mut _ as *const _ };
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -80,7 +66,7 @@ LL | static RAW_MUT_CAST: SyncPtr<i32> = SyncPtr { x : &mut 42 as *mut _ as *con
= note: for more information, see issue #122153 <https://github.com/rust-lang/rust/issues/122153>

error: encountered mutable pointer in final value of static
--> $DIR/static-no-inner-mut.rs:49:1
--> $DIR/static-no-inner-mut.rs:42:1
|
LL | static RAW_MUT_COERCE: SyncPtr<i32> = SyncPtr { x: &mut 0 };
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -96,102 +82,42 @@ help: skipping check that does not even have a feature gate
LL | static REF: &AtomicI32 = &AtomicI32::new(42);
| ^^^^^^^^^^^^^^^^^^^
help: skipping check that does not even have a feature gate
--> $DIR/static-no-inner-mut.rs:13:27
--> $DIR/static-no-inner-mut.rs:12: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:19:56
--> $DIR/static-no-inner-mut.rs:16: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:23:44
--> $DIR/static-no-inner-mut.rs:18: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:41:52
--> $DIR/static-no-inner-mut.rs:34: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:45:51
--> $DIR/static-no-inner-mut.rs:38: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:49:52
--> $DIR/static-no-inner-mut.rs:42:52
|
LL | static RAW_MUT_COERCE: SyncPtr<i32> = SyncPtr { x: &mut 0 };
| ^^^^^^

error: aborting due to 9 previous errors; 1 warning emitted
error: aborting due to 7 previous errors; 1 warning emitted

For more information about this error, try `rustc --explain E0080`.
Future incompatibility report: Future breakage diagnostic:
error: encountered mutable pointer in final value of static
--> $DIR/static-no-inner-mut.rs:9:1
|
LL | static REF: &AtomicI32 = &AtomicI32::new(42);
| ^^^^^^^^^^^^^^^^^^^^^^
|
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
= note: for more information, see issue #122153 <https://github.com/rust-lang/rust/issues/122153>
note: the lint level is defined here
--> $DIR/static-no-inner-mut.rs:6:9
|
LL | #![deny(const_eval_mutable_ptr_in_final_value)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

Future breakage diagnostic:
error: encountered mutable pointer in final value of static
--> $DIR/static-no-inner-mut.rs:13:1
|
LL | static REFMUT: &mut i32 = &mut 0;
| ^^^^^^^^^^^^^^^^^^^^^^^
|
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
= note: for more information, see issue #122153 <https://github.com/rust-lang/rust/issues/122153>
note: the lint level is defined here
--> $DIR/static-no-inner-mut.rs:6:9
|
LL | #![deny(const_eval_mutable_ptr_in_final_value)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

Future breakage diagnostic:
error: encountered mutable pointer in final value of static
--> $DIR/static-no-inner-mut.rs:19:1
|
LL | static REF2: &AtomicI32 = {let x = AtomicI32::new(42); &{x}};
| ^^^^^^^^^^^^^^^^^^^^^^^
|
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
= note: for more information, see issue #122153 <https://github.com/rust-lang/rust/issues/122153>
note: the lint level is defined here
--> $DIR/static-no-inner-mut.rs:6:9
|
LL | #![deny(const_eval_mutable_ptr_in_final_value)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

Future breakage diagnostic:
error: encountered mutable pointer in final value of static
--> $DIR/static-no-inner-mut.rs:23:1
|
LL | static REFMUT2: &mut i32 = {let mut x = 0; &mut {x}};
| ^^^^^^^^^^^^^^^^^^^^^^^^
|
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
= note: for more information, see issue #122153 <https://github.com/rust-lang/rust/issues/122153>
note: the lint level is defined here
--> $DIR/static-no-inner-mut.rs:6:9
|
LL | #![deny(const_eval_mutable_ptr_in_final_value)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

Future breakage diagnostic:
error: encountered mutable pointer in final value of static
--> $DIR/static-no-inner-mut.rs:41:1
--> $DIR/static-no-inner-mut.rs:34:1
|
LL | static RAW_SYNC: SyncPtr<AtomicI32> = SyncPtr { x: &AtomicI32::new(42) };
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -206,7 +132,7 @@ LL | #![deny(const_eval_mutable_ptr_in_final_value)]

Future breakage diagnostic:
error: encountered mutable pointer in final value of static
--> $DIR/static-no-inner-mut.rs:45:1
--> $DIR/static-no-inner-mut.rs:38:1
|
LL | static RAW_MUT_CAST: SyncPtr<i32> = SyncPtr { x : &mut 42 as *mut _ as *const _ };
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -221,7 +147,7 @@ LL | #![deny(const_eval_mutable_ptr_in_final_value)]

Future breakage diagnostic:
error: encountered mutable pointer in final value of static
--> $DIR/static-no-inner-mut.rs:49:1
--> $DIR/static-no-inner-mut.rs:42:1
|
LL | static RAW_MUT_COERCE: SyncPtr<i32> = SyncPtr { x: &mut 0 };
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
144 changes: 35 additions & 109 deletions tests/ui/consts/miri_unleashed/static-no-inner-mut.64bit.stderr
Original file line number Diff line number Diff line change
@@ -1,77 +1,63 @@
error: encountered mutable pointer in final value of static
error[E0080]: it is undefined behavior to use this value
--> $DIR/static-no-inner-mut.rs:9:1
|
LL | static REF: &AtomicI32 = &AtomicI32::new(42);
| ^^^^^^^^^^^^^^^^^^^^^^
|
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
= note: for more information, see issue #122153 <https://github.com/rust-lang/rust/issues/122153>
note: the lint level is defined here
--> $DIR/static-no-inner-mut.rs:6:9
|
LL | #![deny(const_eval_mutable_ptr_in_final_value)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

error: encountered mutable pointer in final value of static
--> $DIR/static-no-inner-mut.rs:13:1
| ^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .<deref>.v: encountered `UnsafeCell` in read-only memory
|
LL | static REFMUT: &mut i32 = &mut 0;
| ^^^^^^^^^^^^^^^^^^^^^^^
|
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
= note: for more information, see issue #122153 <https://github.com/rust-lang/rust/issues/122153>
= 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[E0080]: it is undefined behavior to use this value
--> $DIR/static-no-inner-mut.rs:13:1
--> $DIR/static-no-inner-mut.rs:12:1
|
LL | static REFMUT: &mut i32 = &mut 0;
| ^^^^^^^^^^^^^^^^^^^^^^^ 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: 8) {
ALLOC0╼ │ ╾──────╼
ALLOC1╼ │ ╾──────╼
}

error: encountered mutable pointer in final value of static
--> $DIR/static-no-inner-mut.rs:19:1
error[E0080]: it is undefined behavior to use this value
--> $DIR/static-no-inner-mut.rs:16:1
|
LL | static REF2: &AtomicI32 = {let x = AtomicI32::new(42); &{x}};
| ^^^^^^^^^^^^^^^^^^^^^^^
| ^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .<deref>.v: encountered `UnsafeCell` in read-only memory
|
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
= note: for more information, see issue #122153 <https://github.com/rust-lang/rust/issues/122153>

error: encountered mutable pointer in final value of static
--> $DIR/static-no-inner-mut.rs:23:1
|
LL | static REFMUT2: &mut i32 = {let mut x = 0; &mut {x}};
| ^^^^^^^^^^^^^^^^^^^^^^^^
|
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
= note: for more information, see issue #122153 <https://github.com/rust-lang/rust/issues/122153>
= 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) {
╾ALLOC2╼ │ ╾──────╼
}

error[E0080]: it is undefined behavior to use this value
--> $DIR/static-no-inner-mut.rs:23:1
--> $DIR/static-no-inner-mut.rs:18:1
|
LL | static REFMUT2: &mut i32 = {let mut x = 0; &mut {x}};
| ^^^^^^^^^^^^^^^^^^^^^^^^ 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: 8) {
ALLOC1╼ │ ╾──────╼
ALLOC3╼ │ ╾──────╼
}

error: encountered mutable pointer in final value of static
--> $DIR/static-no-inner-mut.rs:41:1
--> $DIR/static-no-inner-mut.rs:34:1
|
LL | static RAW_SYNC: SyncPtr<AtomicI32> = SyncPtr { x: &AtomicI32::new(42) };
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
= note: for more information, see issue #122153 <https://github.com/rust-lang/rust/issues/122153>
note: the lint level is defined here
--> $DIR/static-no-inner-mut.rs:6:9
|
LL | #![deny(const_eval_mutable_ptr_in_final_value)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

error: encountered mutable pointer in final value of static
--> $DIR/static-no-inner-mut.rs:45:1
--> $DIR/static-no-inner-mut.rs:38:1
|
LL | static RAW_MUT_CAST: SyncPtr<i32> = SyncPtr { x : &mut 42 as *mut _ as *const _ };
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -80,7 +66,7 @@ LL | static RAW_MUT_CAST: SyncPtr<i32> = SyncPtr { x : &mut 42 as *mut _ as *con
= note: for more information, see issue #122153 <https://github.com/rust-lang/rust/issues/122153>

error: encountered mutable pointer in final value of static
--> $DIR/static-no-inner-mut.rs:49:1
--> $DIR/static-no-inner-mut.rs:42:1
|
LL | static RAW_MUT_COERCE: SyncPtr<i32> = SyncPtr { x: &mut 0 };
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -96,102 +82,42 @@ help: skipping check that does not even have a feature gate
LL | static REF: &AtomicI32 = &AtomicI32::new(42);
| ^^^^^^^^^^^^^^^^^^^
help: skipping check that does not even have a feature gate
--> $DIR/static-no-inner-mut.rs:13:27
--> $DIR/static-no-inner-mut.rs:12: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:19:56
--> $DIR/static-no-inner-mut.rs:16: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:23:44
--> $DIR/static-no-inner-mut.rs:18: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:41:52
--> $DIR/static-no-inner-mut.rs:34: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:45:51
--> $DIR/static-no-inner-mut.rs:38: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:49:52
--> $DIR/static-no-inner-mut.rs:42:52
|
LL | static RAW_MUT_COERCE: SyncPtr<i32> = SyncPtr { x: &mut 0 };
| ^^^^^^

error: aborting due to 9 previous errors; 1 warning emitted
error: aborting due to 7 previous errors; 1 warning emitted

For more information about this error, try `rustc --explain E0080`.
Future incompatibility report: Future breakage diagnostic:
error: encountered mutable pointer in final value of static
--> $DIR/static-no-inner-mut.rs:9:1
|
LL | static REF: &AtomicI32 = &AtomicI32::new(42);
| ^^^^^^^^^^^^^^^^^^^^^^
|
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
= note: for more information, see issue #122153 <https://github.com/rust-lang/rust/issues/122153>
note: the lint level is defined here
--> $DIR/static-no-inner-mut.rs:6:9
|
LL | #![deny(const_eval_mutable_ptr_in_final_value)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

Future breakage diagnostic:
error: encountered mutable pointer in final value of static
--> $DIR/static-no-inner-mut.rs:13:1
|
LL | static REFMUT: &mut i32 = &mut 0;
| ^^^^^^^^^^^^^^^^^^^^^^^
|
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
= note: for more information, see issue #122153 <https://github.com/rust-lang/rust/issues/122153>
note: the lint level is defined here
--> $DIR/static-no-inner-mut.rs:6:9
|
LL | #![deny(const_eval_mutable_ptr_in_final_value)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

Future breakage diagnostic:
error: encountered mutable pointer in final value of static
--> $DIR/static-no-inner-mut.rs:19:1
|
LL | static REF2: &AtomicI32 = {let x = AtomicI32::new(42); &{x}};
| ^^^^^^^^^^^^^^^^^^^^^^^
|
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
= note: for more information, see issue #122153 <https://github.com/rust-lang/rust/issues/122153>
note: the lint level is defined here
--> $DIR/static-no-inner-mut.rs:6:9
|
LL | #![deny(const_eval_mutable_ptr_in_final_value)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

Future breakage diagnostic:
error: encountered mutable pointer in final value of static
--> $DIR/static-no-inner-mut.rs:23:1
|
LL | static REFMUT2: &mut i32 = {let mut x = 0; &mut {x}};
| ^^^^^^^^^^^^^^^^^^^^^^^^
|
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
= note: for more information, see issue #122153 <https://github.com/rust-lang/rust/issues/122153>
note: the lint level is defined here
--> $DIR/static-no-inner-mut.rs:6:9
|
LL | #![deny(const_eval_mutable_ptr_in_final_value)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

Future breakage diagnostic:
error: encountered mutable pointer in final value of static
--> $DIR/static-no-inner-mut.rs:41:1
--> $DIR/static-no-inner-mut.rs:34:1
|
LL | static RAW_SYNC: SyncPtr<AtomicI32> = SyncPtr { x: &AtomicI32::new(42) };
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -206,7 +132,7 @@ LL | #![deny(const_eval_mutable_ptr_in_final_value)]

Future breakage diagnostic:
error: encountered mutable pointer in final value of static
--> $DIR/static-no-inner-mut.rs:45:1
--> $DIR/static-no-inner-mut.rs:38:1
|
LL | static RAW_MUT_CAST: SyncPtr<i32> = SyncPtr { x : &mut 42 as *mut _ as *const _ };
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -221,7 +147,7 @@ LL | #![deny(const_eval_mutable_ptr_in_final_value)]

Future breakage diagnostic:
error: encountered mutable pointer in final value of static
--> $DIR/static-no-inner-mut.rs:49:1
--> $DIR/static-no-inner-mut.rs:42:1
|
LL | static RAW_MUT_COERCE: SyncPtr<i32> = SyncPtr { x: &mut 0 };
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
15 changes: 4 additions & 11 deletions tests/ui/consts/miri_unleashed/static-no-inner-mut.rs
Original file line number Diff line number Diff line change
@@ -7,23 +7,16 @@
use std::sync::atomic::*;

static REF: &AtomicI32 = &AtomicI32::new(42);
//~^ ERROR mutable pointer in final value
//~| WARNING this was previously accepted by the compiler
//~^ ERROR it is undefined behavior to use this value

static REFMUT: &mut i32 = &mut 0;
//~^ ERROR mutable pointer in final value
//~| WARNING this was previously accepted by the compiler
//~| ERROR it is undefined behavior to use this value
//~^ ERROR it is undefined behavior to use this value

// Different way of writing this that avoids promotion.
static REF2: &AtomicI32 = {let x = AtomicI32::new(42); &{x}};
//~^ ERROR mutable pointer in final value
//~| WARNING this was previously accepted by the compiler

//~^ ERROR it is undefined behavior to use this value
static REFMUT2: &mut i32 = {let mut x = 0; &mut {x}};
//~^ ERROR mutable pointer in final value
//~| WARNING this was previously accepted by the compiler
//~| ERROR it is undefined behavior to use this value
//~^ ERROR it is undefined behavior to use this value

// This one is obvious, since it is non-Sync. (It also suppresses the other errors, so it is
// commented out.)
21 changes: 21 additions & 0 deletions tests/ui/statics/mutable_memory_validation.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
//issue: rust-lang/rust#122548

// Strip out raw byte dumps to make comparison platform-independent:
//@ normalize-stderr-test "(the raw bytes of the constant) \(size: [0-9]*, align: [0-9]*\)" -> "$1 (size: $$SIZE, align: $$ALIGN)"
//@ normalize-stderr-test "([0-9a-f][0-9a-f] |╾─*A(LLOC)?[0-9]+(\+[a-z0-9]+)?(<imm>)?─*╼ )+ *│.*" -> "HEX_DUMP"

#![feature(const_mut_refs)]
#![feature(const_refs_to_static)]

use std::cell::UnsafeCell;

struct Meh {
x: &'static UnsafeCell<i32>,
}

const MUH: Meh = Meh { x: unsafe { &mut *(&READONLY as *const _ as *mut _) } };
//~^ ERROR: it is undefined behavior to use this value

static READONLY: i32 = 0;

pub fn main() {}
14 changes: 14 additions & 0 deletions tests/ui/statics/mutable_memory_validation.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
error[E0080]: it is undefined behavior to use this value
--> $DIR/mutable_memory_validation.rs:16:1
|
LL | const MUH: Meh = Meh { x: unsafe { &mut *(&READONLY as *const _ as *mut _) } };
| ^^^^^^^^^^^^^^ constructing invalid value at .x.<deref>: encountered `UnsafeCell` in 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: $SIZE, align: $ALIGN) {
HEX_DUMP
}

error: aborting due to 1 previous error

For more information about this error, try `rustc --explain E0080`.