-
Notifications
You must be signed in to change notification settings - Fork 13.5k
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
Changes from all commits
8c9cba2
d87e963
140c9e1
8b2a4f8
77fe9f0
126dcc6
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
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 | ||
oli-obk marked this conversation as resolved.
Show resolved
Hide resolved
|
||
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 | ||
RalfJung marked this conversation as resolved.
Show resolved
Hide resolved
|
||
} 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) { | ||
oli-obk marked this conversation as resolved.
Show resolved
Hide resolved
|
||
assert_eq!(alloc.mutability, mutability); | ||
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. Can this assertion be moved outside the 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. There will never be an entry for nested statics. They have already been interned. I'll assert that there is no such entry. 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. Ah I had not even noticed that this specifically checks the The only thing that has not been interned here is the root alloc of a static, right? 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 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 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. I am confused -- I thought we use the same AllocId for the return place as for the static? 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. Hmm right. No idea where the cycle errors are coming from then. I just tested it and they still occur. 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. If you called 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. 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 | ||
} | ||
} | ||
} | ||
|
||
|
This file was deleted.
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`. |
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() {} |
Large diffs are not rendered by default.
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 | ||
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. 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 }; | ||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | ||
|
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() {} |
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`. |
Uh oh!
There was an error while loading. Please reload this page.