add const_make_global; err for const_allocate ptrs if didn't call

Co-Authored-By: Ralf Jung <post@ralfj.de>
Co-Authored-By: Oli Scherer <github333195615777966@oli-obk.de>
This commit is contained in:
Deadbeef 2025-07-08 00:20:57 +08:00
parent 9c3064e131
commit 3f2dc2bd1a
31 changed files with 361 additions and 30 deletions

View file

@ -56,6 +56,17 @@ const_eval_const_context = {$kind ->
*[other] {""}
}
const_eval_const_heap_ptr_in_final = encountered `const_allocate` pointer in final value that was not made global
.note = use `const_make_global` to make allocated pointers immutable before returning
const_eval_const_make_global_ptr_already_made_global = attempting to call `const_make_global` twice on the same allocation {$alloc}
const_eval_const_make_global_ptr_is_non_heap = pointer passed to `const_make_global` does not point to a heap allocation: {$ptr}
const_eval_const_make_global_with_dangling_ptr = pointer passed to `const_make_global` is dangling: {$ptr}
const_eval_const_make_global_with_offset = making {$ptr} global which does not point to the beginning of an object
const_eval_copy_nonoverlapping_overlapping =
`copy_nonoverlapping` called on overlapping ranges

View file

@ -2,7 +2,7 @@ use std::mem;
use rustc_errors::{Diag, DiagArgName, DiagArgValue, DiagMessage, IntoDiagArg};
use rustc_middle::mir::AssertKind;
use rustc_middle::mir::interpret::{Provenance, ReportedErrorInfo};
use rustc_middle::mir::interpret::{AllocId, Provenance, ReportedErrorInfo};
use rustc_middle::query::TyCtxtAt;
use rustc_middle::ty::layout::LayoutError;
use rustc_middle::ty::{ConstInt, TyCtxt};
@ -22,8 +22,22 @@ pub enum ConstEvalErrKind {
ModifiedGlobal,
RecursiveStatic,
AssertFailure(AssertKind<ConstInt>),
Panic { msg: Symbol, line: u32, col: u32, file: Symbol },
Panic {
msg: Symbol,
line: u32,
col: u32,
file: Symbol,
},
WriteThroughImmutablePointer,
/// Called `const_make_global` twice.
ConstMakeGlobalPtrAlreadyMadeGlobal(AllocId),
/// Called `const_make_global` on a non-heap pointer.
ConstMakeGlobalPtrIsNonHeap(String),
/// Called `const_make_global` on a dangling pointer.
ConstMakeGlobalWithDanglingPtr(String),
/// Called `const_make_global` on a pointer that does not start at the
/// beginning of an object.
ConstMakeGlobalWithOffset(String),
}
impl MachineStopType for ConstEvalErrKind {
@ -38,6 +52,12 @@ impl MachineStopType for ConstEvalErrKind {
RecursiveStatic => const_eval_recursive_static,
AssertFailure(x) => x.diagnostic_message(),
WriteThroughImmutablePointer => const_eval_write_through_immutable_pointer,
ConstMakeGlobalPtrAlreadyMadeGlobal { .. } => {
const_eval_const_make_global_ptr_already_made_global
}
ConstMakeGlobalPtrIsNonHeap(_) => const_eval_const_make_global_ptr_is_non_heap,
ConstMakeGlobalWithDanglingPtr(_) => const_eval_const_make_global_with_dangling_ptr,
ConstMakeGlobalWithOffset(_) => const_eval_const_make_global_with_offset,
}
}
fn add_args(self: Box<Self>, adder: &mut dyn FnMut(DiagArgName, DiagArgValue)) {
@ -51,6 +71,14 @@ impl MachineStopType for ConstEvalErrKind {
Panic { msg, .. } => {
adder("msg".into(), msg.into_diag_arg(&mut None));
}
ConstMakeGlobalPtrIsNonHeap(ptr)
| ConstMakeGlobalWithOffset(ptr)
| ConstMakeGlobalWithDanglingPtr(ptr) => {
adder("ptr".into(), ptr.into_diag_arg(&mut None));
}
ConstMakeGlobalPtrAlreadyMadeGlobal(alloc) => {
adder("alloc".into(), alloc.into_diag_arg(&mut None));
}
}
}
}

View file

@ -93,7 +93,7 @@ fn eval_body_using_ecx<'tcx, R: InterpretationResult<'tcx>>(
// 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.
// Only report this after validation, as validation produces much better diagnostics.
// FIXME: ensure validation always reports this and stop making interning care about it.
match intern_result {

View file

@ -169,13 +169,15 @@ pub type CompileTimeInterpCx<'tcx> = InterpCx<'tcx, CompileTimeMachine<'tcx>>;
#[derive(Debug, PartialEq, Eq, Copy, Clone)]
pub enum MemoryKind {
Heap,
Heap { was_made_global: bool },
}
impl fmt::Display for MemoryKind {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
MemoryKind::Heap => write!(f, "heap allocation"),
MemoryKind::Heap { was_made_global } => {
write!(f, "heap allocation{}", if *was_made_global { " (made global)" } else { "" })
}
}
}
}
@ -184,7 +186,7 @@ impl interpret::MayLeak for MemoryKind {
#[inline(always)]
fn may_leak(self) -> bool {
match self {
MemoryKind::Heap => false,
MemoryKind::Heap { was_made_global } => was_made_global,
}
}
}
@ -420,7 +422,7 @@ impl<'tcx> interpret::Machine<'tcx> for CompileTimeMachine<'tcx> {
let ptr = ecx.allocate_ptr(
Size::from_bytes(size),
align,
interpret::MemoryKind::Machine(MemoryKind::Heap),
interpret::MemoryKind::Machine(MemoryKind::Heap { was_made_global: false }),
AllocInit::Uninit,
)?;
ecx.write_pointer(ptr, dest)?;
@ -453,10 +455,17 @@ impl<'tcx> interpret::Machine<'tcx> for CompileTimeMachine<'tcx> {
ecx.deallocate_ptr(
ptr,
Some((size, align)),
interpret::MemoryKind::Machine(MemoryKind::Heap),
interpret::MemoryKind::Machine(MemoryKind::Heap { was_made_global: false }),
)?;
}
}
sym::const_make_global => {
let ptr = ecx.read_pointer(&args[0])?;
ecx.make_const_heap_ptr_global(ptr)?;
ecx.write_pointer(ptr, dest)?;
}
// The intrinsic represents whether the value is known to the optimizer (LLVM).
// We're not doing any optimizations here, so there is no optimizer that could know the value.
// (We know the value here in the machine of course, but this is the runtime of that code,

View file

@ -43,6 +43,14 @@ pub(crate) struct MutablePtrInFinal {
pub kind: InternKind,
}
#[derive(Diagnostic)]
#[diag(const_eval_const_heap_ptr_in_final)]
#[note]
pub(crate) struct ConstHeapPtrInFinal {
#[primary_span]
pub span: Span,
}
#[derive(Diagnostic)]
#[diag(const_eval_unstable_in_stable_exposed)]
pub(crate) struct UnstableInStableExposed {

View file

@ -31,7 +31,7 @@ use super::{
};
use crate::const_eval;
use crate::const_eval::DummyMachine;
use crate::errors::NestedStaticInThreadLocal;
use crate::errors::{ConstHeapPtrInFinal, NestedStaticInThreadLocal};
pub trait CompileTimeMachine<'tcx, T> = Machine<
'tcx,
@ -55,6 +55,35 @@ impl HasStaticRootDefId for const_eval::CompileTimeMachine<'_> {
}
}
pub enum DisallowInternReason {
ConstHeap,
}
/// A trait for controlling whether memory allocated in the interpreter can be interned.
///
/// This prevents us from interning `const_allocate` pointers that have not been made
/// global through `const_make_global`.
pub trait CanIntern {
fn disallows_intern(&self) -> Option<DisallowInternReason>;
}
impl CanIntern for const_eval::MemoryKind {
fn disallows_intern(&self) -> Option<DisallowInternReason> {
match self {
const_eval::MemoryKind::Heap { was_made_global: false } => {
Some(DisallowInternReason::ConstHeap)
}
const_eval::MemoryKind::Heap { was_made_global: true } => None,
}
}
}
impl CanIntern for ! {
fn disallows_intern(&self) -> Option<DisallowInternReason> {
*self
}
}
/// Intern an allocation. Returns `Err` if the allocation does not exist in the local memory.
///
/// `mutability` can be used to force immutable interning: if it is `Mutability::Not`, the
@ -62,7 +91,7 @@ impl HasStaticRootDefId for const_eval::CompileTimeMachine<'_> {
/// already mutable (as a sanity check).
///
/// Returns an iterator over all relocations referred to by this allocation.
fn intern_shallow<'tcx, T, M: CompileTimeMachine<'tcx, T>>(
fn intern_shallow<'tcx, T: CanIntern, M: CompileTimeMachine<'tcx, T>>(
ecx: &mut InterpCx<'tcx, M>,
alloc_id: AllocId,
mutability: Mutability,
@ -71,9 +100,26 @@ fn intern_shallow<'tcx, T, M: CompileTimeMachine<'tcx, T>>(
trace!("intern_shallow {:?}", alloc_id);
// remove allocation
// FIXME(#120456) - is `swap_remove` correct?
let Some((_kind, mut alloc)) = ecx.memory.alloc_map.swap_remove(&alloc_id) else {
let Some((kind, mut alloc)) = ecx.memory.alloc_map.swap_remove(&alloc_id) else {
return Err(());
};
match kind {
MemoryKind::Machine(x) if let Some(reason) = x.disallows_intern() => match reason {
// attempting to intern a `const_allocate`d pointer that was not made global via
// `const_make_global`. We emit an error here but don't return an `Err`. The `Err`
// is for pointers that we can't intern at all (i.e. dangling pointers). We still
// (recursively) intern this pointer because we don't have to worry about the
// additional paperwork involved with _not_ interning it, such as storing it in
// the dead memory map and having to deal with additional "dangling pointer"
// messages if someone tries to store the non-made-global ptr in the final value.
DisallowInternReason::ConstHeap => {
ecx.tcx.dcx().emit_err(ConstHeapPtrInFinal { span: ecx.tcx.span });
}
},
MemoryKind::Machine(_) | MemoryKind::Stack | MemoryKind::CallerLocation => {}
}
// Set allocation mutability as appropriate. This is used by LLVM to put things into
// read-only memory, and also by Miri when evaluating other globals that
// access this one.
@ -99,7 +145,7 @@ fn intern_shallow<'tcx, T, M: CompileTimeMachine<'tcx, T>>(
} else {
ecx.tcx.set_alloc_id_memory(alloc_id, alloc);
}
Ok(alloc.0.0.provenance().ptrs().iter().map(|&(_, prov)| prov))
Ok(alloc.inner().provenance().ptrs().iter().map(|&(_, prov)| prov))
}
/// Creates a new `DefId` and feeds all the right queries to make this `DefId`
@ -181,7 +227,7 @@ pub fn intern_const_alloc_recursive<'tcx, M: CompileTimeMachine<'tcx, const_eval
}
InternKind::Static(Mutability::Not) => {
(
// Outermost allocation is mutable if `!Freeze`.
// Outermost allocation is mutable if `!Freeze` i.e. contains interior mutable types.
if ret.layout.ty.is_freeze(*ecx.tcx, ecx.typing_env) {
Mutability::Not
} else {
@ -321,7 +367,7 @@ pub fn intern_const_alloc_recursive<'tcx, M: CompileTimeMachine<'tcx, const_eval
/// Intern `ret`. This function assumes that `ret` references no other allocation.
#[instrument(level = "debug", skip(ecx))]
pub fn intern_const_alloc_for_constprop<'tcx, T, M: CompileTimeMachine<'tcx, T>>(
pub fn intern_const_alloc_for_constprop<'tcx, T: CanIntern, M: CompileTimeMachine<'tcx, T>>(
ecx: &mut InterpCx<'tcx, M>,
alloc_id: AllocId,
) -> InterpResult<'tcx, ()> {

View file

@ -26,6 +26,7 @@ use super::{
Misalignment, Pointer, PointerArithmetic, Provenance, Scalar, alloc_range, err_ub,
err_ub_custom, interp_ok, throw_ub, throw_ub_custom, throw_unsup, throw_unsup_format,
};
use crate::const_eval::ConstEvalErrKind;
use crate::fluent_generated as fluent;
#[derive(Debug, PartialEq, Copy, Clone)]
@ -311,6 +312,49 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
interp_ok(new_ptr)
}
/// mark the `const_allocate`d pointer immutable so we can intern it.
pub fn make_const_heap_ptr_global(
&mut self,
ptr: Pointer<Option<M::Provenance>>,
) -> InterpResult<'tcx>
where
M: Machine<'tcx, MemoryKind = crate::const_eval::MemoryKind>,
{
let (alloc_id, offset, _) = self.ptr_get_alloc_id(ptr, 0)?;
if offset.bytes() != 0 {
return Err(ConstEvalErrKind::ConstMakeGlobalWithOffset(format!("{ptr:?}"))).into();
}
let not_local_heap =
matches!(self.tcx.try_get_global_alloc(alloc_id), Some(GlobalAlloc::Memory(_)));
if not_local_heap {
return Err(ConstEvalErrKind::ConstMakeGlobalPtrIsNonHeap(format!("{ptr:?}"))).into();
}
let (kind, alloc) = self.memory.alloc_map.get_mut_or(alloc_id, || {
Err(ConstEvalErrKind::ConstMakeGlobalWithDanglingPtr(format!("{ptr:?}")))
})?;
alloc.mutability = Mutability::Not;
match kind {
MemoryKind::Stack | MemoryKind::CallerLocation => {
return Err(ConstEvalErrKind::ConstMakeGlobalPtrIsNonHeap(format!("{ptr:?}")))
.into();
}
MemoryKind::Machine(crate::const_eval::MemoryKind::Heap { was_made_global }) => {
if *was_made_global {
return Err(ConstEvalErrKind::ConstMakeGlobalPtrAlreadyMadeGlobal(alloc_id))
.into();
}
*was_made_global = true;
}
}
interp_ok(())
}
#[instrument(skip(self), level = "debug")]
pub fn deallocate_ptr(
&mut self,

View file

@ -52,9 +52,8 @@ fn check_validity_requirement_strict<'tcx>(
let mut cx = InterpCx::new(cx.tcx(), DUMMY_SP, cx.typing_env, machine);
let allocated = cx
.allocate(ty, MemoryKind::Machine(crate::const_eval::MemoryKind::Heap))
.expect("OOM: failed to allocate for uninit check");
let allocated =
cx.allocate(ty, MemoryKind::Stack).expect("OOM: failed to allocate for uninit check");
if kind == ValidityRequirement::Zero {
cx.write_bytes_ptr(
@ -185,7 +184,10 @@ pub(crate) fn validate_scalar_in_layout<'tcx>(
bug!("could not compute layout of {scalar:?}:{ty:?}")
};
let allocated = cx
.allocate(layout, MemoryKind::Machine(crate::const_eval::MemoryKind::Heap))
.allocate(
layout,
MemoryKind::Machine(crate::const_eval::MemoryKind::Heap { was_made_global: false }),
)
.expect("OOM: failed to allocate for uninit check");
cx.write_scalar(scalar, &allocated).unwrap();

View file

@ -422,6 +422,9 @@ pub(crate) fn check_intrinsic_type(
vec![Ty::new_mut_ptr(tcx, tcx.types.u8), tcx.types.usize, tcx.types.usize],
tcx.types.unit,
),
sym::const_make_global => {
(0, 0, vec![Ty::new_mut_ptr(tcx, tcx.types.u8)], Ty::new_imm_ptr(tcx, tcx.types.u8))
}
sym::ptr_offset_from => (
1,

View file

@ -257,7 +257,7 @@ pub enum InvalidProgramInfo<'tcx> {
/// Details of why a pointer had to be in-bounds.
#[derive(Debug, Copy, Clone)]
pub enum CheckInAllocMsg {
/// We are access memory.
/// We are accessing memory.
MemoryAccess,
/// We are doing pointer arithmetic.
InboundsPointerArithmetic,

View file

@ -715,6 +715,7 @@ symbols! {
const_indexing,
const_let,
const_loop,
const_make_global,
const_mut_refs,
const_panic,
const_panic_fmt,

View file

@ -5,7 +5,7 @@
use core::error::Error;
use core::fmt::{self, Debug, Display, Formatter};
#[cfg(not(no_global_oom_handling))]
use core::intrinsics::const_allocate;
use core::intrinsics::{const_allocate, const_make_global};
use core::marker::PhantomData;
#[cfg(not(no_global_oom_handling))]
use core::marker::Unsize;
@ -340,9 +340,10 @@ impl<H> WithHeader<H> {
alloc.add(metadata_offset).cast();
// SAFETY: `*metadata_ptr` is within the allocation.
metadata_ptr.write(ptr::metadata::<Dyn>(ptr::dangling::<T>() as *const Dyn));
// SAFETY: valid heap allocation
const_make_global(alloc);
// SAFETY: we have just written the metadata.
&*(metadata_ptr)
&*metadata_ptr
}
};

View file

@ -2533,6 +2533,15 @@ pub const unsafe fn const_deallocate(_ptr: *mut u8, _size: usize, _align: usize)
// Runtime NOP
}
#[rustc_const_unstable(feature = "const_heap", issue = "79597")]
#[rustc_nounwind]
#[rustc_intrinsic]
#[miri::intrinsic_fallback_is_spec]
pub const unsafe fn const_make_global(ptr: *mut u8) -> *const u8 {
// const eval overrides this function; at runtime, it is a NOP.
ptr
}
/// Returns whether we should perform contract-checking at runtime.
///
/// This is meant to be similar to the ub_checks intrinsic, in terms

View file

@ -8,11 +8,11 @@ const FOO_RAW: *const i32 = foo();
const fn foo() -> &'static i32 {
let t = unsafe {
let i = intrinsics::const_allocate(4, 4) as * mut i32;
let i = intrinsics::const_allocate(4, 4) as *mut i32;
*i = 20;
i
};
unsafe { &*t }
unsafe { &*(intrinsics::const_make_global(t as *mut u8) as *mut i32) }
}
fn main() {
assert_eq!(*FOO, 20);

View file

@ -1,7 +1,7 @@
error[E0080]: constructing invalid value at .<deref>: encountered uninitialized memory, but expected an integer
--> $DIR/alloc_intrinsic_uninit.rs:7:1
|
LL | const BAR: &i32 = unsafe { &*(intrinsics::const_allocate(4, 4) as *mut i32) };
LL | const BAR: &i32 = unsafe {
| ^^^^^^^^^^^^^^^ it is undefined behavior to use this 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.

View file

@ -1,7 +1,7 @@
error[E0080]: constructing invalid value at .<deref>: encountered uninitialized memory, but expected an integer
--> $DIR/alloc_intrinsic_uninit.rs:7:1
|
LL | const BAR: &i32 = unsafe { &*(intrinsics::const_allocate(4, 4) as *mut i32) };
LL | const BAR: &i32 = unsafe {
| ^^^^^^^^^^^^^^^ it is undefined behavior to use this 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.

View file

@ -4,6 +4,7 @@
#![feature(const_heap)]
use std::intrinsics;
const BAR: &i32 = unsafe { &*(intrinsics::const_allocate(4, 4) as *mut i32) };
//~^ ERROR: uninitialized memory
const BAR: &i32 = unsafe { //~ ERROR: uninitialized memory
&*(intrinsics::const_make_global(intrinsics::const_allocate(4, 4)) as *mut i32)
};
fn main() {}

View file

@ -7,5 +7,6 @@ use std::intrinsics;
const BAR: *mut i32 = unsafe { intrinsics::const_allocate(4, 4) as *mut i32 };
//~^ error: mutable pointer in final value of constant
//~| error: encountered `const_allocate` pointer in final value that was not made global
fn main() {}

View file

@ -1,8 +1,16 @@
error: encountered `const_allocate` pointer in final value that was not made global
--> $DIR/alloc_intrinsic_untyped.rs:8:1
|
LL | const BAR: *mut i32 = unsafe { intrinsics::const_allocate(4, 4) as *mut i32 };
| ^^^^^^^^^^^^^^^^^^^
|
= note: use `const_make_global` to make allocated pointers immutable before returning
error: encountered mutable pointer in final value of constant
--> $DIR/alloc_intrinsic_untyped.rs:8:1
|
LL | const BAR: *mut i32 = unsafe { intrinsics::const_allocate(4, 4) as *mut i32 };
| ^^^^^^^^^^^^^^^^^^^
error: aborting due to 1 previous error
error: aborting due to 2 previous errors

View file

@ -12,7 +12,7 @@ const _X: () = unsafe {
const Y: &u32 = unsafe {
let ptr = intrinsics::const_allocate(4, 4) as *mut u32;
*ptr = 42;
&*ptr
&*(intrinsics::const_make_global(ptr as *mut u8) as *const u32)
};
const Z: &u32 = &42;

View file

@ -0,0 +1,16 @@
#![feature(core_intrinsics)]
#![feature(const_heap)]
use std::intrinsics;
const Y: &u32 = unsafe {
&*(intrinsics::const_make_global(std::ptr::null_mut()) as *const u32)
//~^ error: pointer not dereferenceable
};
const Z: &u32 = unsafe {
&*(intrinsics::const_make_global(std::ptr::dangling_mut()) as *const u32)
//~^ error: pointer not dereferenceable
};
fn main() {}

View file

@ -0,0 +1,15 @@
error[E0080]: pointer not dereferenceable: pointer must point to some allocation, but got null pointer
--> $DIR/make-global-dangling.rs:7:8
|
LL | &*(intrinsics::const_make_global(std::ptr::null_mut()) as *const u32)
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of `Y` failed here
error[E0080]: pointer not dereferenceable: pointer must point to some allocation, but got 0x1[noalloc] which is a dangling pointer (it has no provenance)
--> $DIR/make-global-dangling.rs:12:8
|
LL | &*(intrinsics::const_make_global(std::ptr::dangling_mut()) as *const u32)
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of `Z` failed here
error: aborting due to 2 previous errors
For more information about this error, try `rustc --explain E0080`.

View file

@ -0,0 +1,13 @@
#![feature(core_intrinsics)]
#![feature(const_heap)]
use std::intrinsics;
const X: &i32 = &0;
const Y: &i32 = unsafe {
&*(intrinsics::const_make_global(X as *const i32 as *mut u8) as *const i32)
//~^ error: pointer passed to `const_make_global` does not point to a heap allocation: ALLOC0<imm>
};
fn main() {}

View file

@ -0,0 +1,9 @@
error[E0080]: pointer passed to `const_make_global` does not point to a heap allocation: ALLOC0<imm>
--> $DIR/make-global-other.rs:9:8
|
LL | &*(intrinsics::const_make_global(X as *const i32 as *mut u8) as *const i32)
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of `Y` failed here
error: aborting due to 1 previous error
For more information about this error, try `rustc --explain E0080`.

View file

@ -0,0 +1,16 @@
#![feature(core_intrinsics)]
#![feature(const_heap)]
use std::intrinsics;
const Y: &i32 = unsafe {
let ptr = intrinsics::const_allocate(4, 4);
let i = ptr as *mut i32;
*i = 20;
intrinsics::const_make_global(ptr);
intrinsics::const_make_global(ptr);
//~^ error: attempting to call `const_make_global` twice on the same allocation ALLOC0
&*i
};
fn main() {}

View file

@ -0,0 +1,9 @@
error[E0080]: attempting to call `const_make_global` twice on the same allocation ALLOC0
--> $DIR/make-global-twice.rs:11:5
|
LL | intrinsics::const_make_global(ptr);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of `Y` failed here
error: aborting due to 1 previous error
For more information about this error, try `rustc --explain E0080`.

View file

@ -0,0 +1,21 @@
//@ run-pass
#![feature(core_intrinsics)]
#![feature(const_heap)]
use std::intrinsics;
const FOO: &i32 = foo();
const FOO_RAW: *const i32 = foo();
const fn foo() -> &'static i32 {
unsafe {
let ptr = intrinsics::const_allocate(4, 4);
let t = ptr as *mut i32;
*t = 20;
intrinsics::const_make_global(ptr);
&*t
}
}
fn main() {
assert_eq!(*FOO, 20);
assert_eq!(unsafe { *FOO_RAW }, 20);
}

View file

@ -0,0 +1,14 @@
#![feature(core_intrinsics)]
#![feature(const_heap)]
use std::intrinsics;
const A: &u8 = unsafe {
let ptr = intrinsics::const_allocate(1, 1);
*ptr = 1;
let ptr: *const u8 = intrinsics::const_make_global(ptr);
*(ptr as *mut u8) = 2;
//~^ error: writing to ALLOC0 which is read-only
&*ptr
};
fn main() {}

View file

@ -0,0 +1,9 @@
error[E0080]: writing to ALLOC0 which is read-only
--> $DIR/ptr_made_global_mutated.rs:9:5
|
LL | *(ptr as *mut u8) = 2;
| ^^^^^^^^^^^^^^^^^^^^^ evaluation of `A` failed here
error: aborting due to 1 previous error
For more information about this error, try `rustc --explain E0080`.

View file

@ -0,0 +1,19 @@
#![feature(core_intrinsics)]
#![feature(const_heap)]
use std::intrinsics;
const FOO: &i32 = foo();
//~^ error: encountered `const_allocate` pointer in final value that was not made global
const FOO_RAW: *const i32 = foo();
//~^ error: encountered `const_allocate` pointer in final value that was not made global
const fn foo() -> &'static i32 {
let t = unsafe {
let i = intrinsics::const_allocate(4, 4) as *mut i32;
*i = 20;
i
};
unsafe { &*t }
}
fn main() {}

View file

@ -0,0 +1,18 @@
error: encountered `const_allocate` pointer in final value that was not made global
--> $DIR/ptr_not_made_global.rs:5:1
|
LL | const FOO: &i32 = foo();
| ^^^^^^^^^^^^^^^
|
= note: use `const_make_global` to make allocated pointers immutable before returning
error: encountered `const_allocate` pointer in final value that was not made global
--> $DIR/ptr_not_made_global.rs:7:1
|
LL | const FOO_RAW: *const i32 = foo();
| ^^^^^^^^^^^^^^^^^^^^^^^^^
|
= note: use `const_make_global` to make allocated pointers immutable before returning
error: aborting due to 2 previous errors