add const_allocate intrisic
This commit is contained in:
parent
b7ebc6b0c1
commit
528355c541
@ -104,7 +104,7 @@ fn intern_shallow<'rt, 'mir, 'tcx, M: CompileTimeMachine<'mir, 'tcx>>(
|
||||
// This match is just a canary for future changes to `MemoryKind`, which most likely need
|
||||
// changes in this function.
|
||||
match kind {
|
||||
MemoryKind::Stack | MemoryKind::Vtable | MemoryKind::CallerLocation => {}
|
||||
MemoryKind::Stack | MemoryKind::Heap | MemoryKind::Vtable | 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
|
||||
|
@ -14,10 +14,11 @@ use rustc_middle::ty;
|
||||
use rustc_middle::ty::subst::SubstsRef;
|
||||
use rustc_middle::ty::{Ty, TyCtxt};
|
||||
use rustc_span::symbol::{sym, Symbol};
|
||||
use rustc_target::abi::{Abi, LayoutOf as _, Primitive, Size};
|
||||
use rustc_target::abi::{Abi, Align, LayoutOf as _, Primitive, Size};
|
||||
|
||||
use super::{
|
||||
util::ensure_monomorphic_enough, CheckInAllocMsg, ImmTy, InterpCx, Machine, OpTy, PlaceTy,
|
||||
util::ensure_monomorphic_enough, CheckInAllocMsg, ImmTy, InterpCx, Machine, MemoryKind, OpTy,
|
||||
PlaceTy,
|
||||
};
|
||||
|
||||
mod caller_location;
|
||||
@ -337,6 +338,19 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
||||
let result = Scalar::from_uint(truncated_bits, layout.size);
|
||||
self.write_scalar(result, dest)?;
|
||||
}
|
||||
sym::const_allocate => {
|
||||
let size = self.read_scalar(args[0])?.to_machine_usize(self)?;
|
||||
let align = self.read_scalar(args[1])?.to_machine_usize(self)?;
|
||||
|
||||
let align = match Align::from_bytes(align) {
|
||||
Ok(a) => a,
|
||||
Err(err) => bug!("align has to power of 2, {}", err),
|
||||
};
|
||||
|
||||
let ptr =
|
||||
self.memory.allocate(Size::from_bytes(size as u64), align, MemoryKind::Heap);
|
||||
self.write_scalar(Scalar::Ptr(ptr), dest)?;
|
||||
}
|
||||
sym::offset => {
|
||||
let ptr = self.read_scalar(args[0])?.check_init()?;
|
||||
let offset_count = self.read_scalar(args[1])?.to_machine_isize(self)?;
|
||||
|
@ -27,6 +27,8 @@ use crate::util::pretty;
|
||||
pub enum MemoryKind<T> {
|
||||
/// Stack memory. Error if deallocated except during a stack pop.
|
||||
Stack,
|
||||
/// Heap memory.
|
||||
Heap,
|
||||
/// Memory backing vtables. Error if ever deallocated.
|
||||
Vtable,
|
||||
/// Memory allocated by `caller_location` intrinsic. Error if ever deallocated.
|
||||
@ -40,6 +42,7 @@ impl<T: MayLeak> MayLeak for MemoryKind<T> {
|
||||
fn may_leak(self) -> bool {
|
||||
match self {
|
||||
MemoryKind::Stack => false,
|
||||
MemoryKind::Heap => true,
|
||||
MemoryKind::Vtable => true,
|
||||
MemoryKind::CallerLocation => true,
|
||||
MemoryKind::Machine(k) => k.may_leak(),
|
||||
@ -51,6 +54,7 @@ impl<T: fmt::Display> fmt::Display for MemoryKind<T> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
match self {
|
||||
MemoryKind::Stack => write!(f, "stack variable"),
|
||||
MemoryKind::Heap => write!(f, "heap variable"),
|
||||
MemoryKind::Vtable => write!(f, "vtable"),
|
||||
MemoryKind::CallerLocation => write!(f, "caller location"),
|
||||
MemoryKind::Machine(m) => write!(f, "{}", m),
|
||||
|
@ -356,6 +356,7 @@ symbols! {
|
||||
concat_idents,
|
||||
conservative_impl_trait,
|
||||
console,
|
||||
const_allocate,
|
||||
const_compare_raw_pointers,
|
||||
const_constructor,
|
||||
const_eval_limit,
|
||||
|
@ -286,6 +286,10 @@ pub fn check_intrinsic_type(tcx: TyCtxt<'_>, it: &hir::ForeignItem<'_>) {
|
||||
(1, vec![tcx.mk_imm_ptr(param(0)), tcx.mk_imm_ptr(param(0))], tcx.types.bool)
|
||||
}
|
||||
|
||||
sym::const_allocate => {
|
||||
(0, vec![tcx.types.usize, tcx.types.usize], tcx.mk_mut_ptr(tcx.types.u8))
|
||||
}
|
||||
|
||||
sym::ptr_offset_from => {
|
||||
(1, vec![tcx.mk_imm_ptr(param(0)), tcx.mk_imm_ptr(param(0))], tcx.types.isize)
|
||||
}
|
||||
|
@ -1732,6 +1732,11 @@ extern "rust-intrinsic" {
|
||||
/// See documentation of `<*const T>::guaranteed_ne` for details.
|
||||
#[rustc_const_unstable(feature = "const_raw_ptr_comparison", issue = "53020")]
|
||||
pub fn ptr_guaranteed_ne<T>(ptr: *const T, other: *const T) -> bool;
|
||||
|
||||
/// Allocate at compile time. Should not be called at runtime.
|
||||
#[rustc_const_unstable(feature = "const_heap", issue = "none")]
|
||||
#[cfg(not(bootstrap))]
|
||||
pub fn const_allocate(size: usize, align: usize) -> *mut u8;
|
||||
}
|
||||
|
||||
// Some functions are defined here because they accidentally got made
|
||||
|
@ -68,6 +68,7 @@
|
||||
#![feature(arbitrary_self_types)]
|
||||
#![feature(asm)]
|
||||
#![feature(cfg_target_has_atomic)]
|
||||
#![cfg_attr(not(bootstrap), feature(const_heap))]
|
||||
#![feature(const_alloc_layout)]
|
||||
#![feature(const_discriminant)]
|
||||
#![feature(const_cell_into_inner)]
|
||||
|
@ -0,0 +1,20 @@
|
||||
// run-pass
|
||||
#![feature(core_intrinsics)]
|
||||
#![feature(const_heap)]
|
||||
#![feature(const_raw_ptr_deref)]
|
||||
#![feature(const_mut_refs)]
|
||||
use std::intrinsics;
|
||||
|
||||
const FOO: *const i32 = foo();
|
||||
|
||||
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() {
|
||||
assert_eq!(unsafe { *FOO }, 20)
|
||||
}
|
@ -0,0 +1,20 @@
|
||||
// run-pass
|
||||
#![feature(core_intrinsics)]
|
||||
#![feature(const_heap)]
|
||||
#![feature(const_raw_ptr_deref)]
|
||||
#![feature(const_mut_refs)]
|
||||
use std::intrinsics;
|
||||
|
||||
const FOO: i32 = foo();
|
||||
|
||||
const fn foo() -> i32 {
|
||||
let t = unsafe {
|
||||
let i = intrinsics::const_allocate(4, 4) as * mut i32;
|
||||
*i = 20;
|
||||
i
|
||||
};
|
||||
unsafe { *t }
|
||||
}
|
||||
fn main() {
|
||||
assert_eq!(FOO, 20);
|
||||
}
|
10
src/test/ui/consts/const-eval/heap/alloc_intrinsic_uninit.rs
Normal file
10
src/test/ui/consts/const-eval/heap/alloc_intrinsic_uninit.rs
Normal file
@ -0,0 +1,10 @@
|
||||
// compile-test
|
||||
#![feature(core_intrinsics)]
|
||||
#![feature(const_heap)]
|
||||
#![feature(const_raw_ptr_deref)]
|
||||
#![feature(const_mut_refs)]
|
||||
use std::intrinsics;
|
||||
|
||||
const BAR: &i32 = unsafe { &*(intrinsics::const_allocate(4, 4) as *mut i32) };
|
||||
//~^ error: it is undefined behavior to use this value
|
||||
fn main() {}
|
@ -0,0 +1,11 @@
|
||||
error[E0080]: it is undefined behavior to use this value
|
||||
--> $DIR/alloc_intrinsic_uninit.rs:8:1
|
||||
|
|
||||
LL | const BAR: &i32 = unsafe { &*(intrinsics::const_allocate(4, 4) as *mut i32) };
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered uninitialized bytes at .<deref>, but expected initialized plain (non-pointer) bytes
|
||||
|
|
||||
= 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.
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
For more information about this error, try `rustc --explain E0080`.
|
@ -0,0 +1,10 @@
|
||||
#![feature(core_intrinsics)]
|
||||
#![feature(const_heap)]
|
||||
#![feature(const_raw_ptr_deref)]
|
||||
#![feature(const_mut_refs)]
|
||||
use std::intrinsics;
|
||||
|
||||
const BAR: *mut i32 = unsafe { intrinsics::const_allocate(4, 4) as *mut i32};
|
||||
//~^ error: untyped pointers are not allowed in constant
|
||||
|
||||
fn main() {}
|
@ -0,0 +1,8 @@
|
||||
error: untyped pointers are not allowed in constant
|
||||
--> $DIR/alloc_intrinsic_untyped.rs:7:1
|
||||
|
|
||||
LL | const BAR: *mut i32 = unsafe { intrinsics::const_allocate(4, 4) as *mut i32};
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: aborting due to previous error
|
||||
|
Loading…
Reference in New Issue
Block a user