add const_allocate intrisic

This commit is contained in:
Vishnunarayan K I 2020-12-01 15:39:25 +05:30
parent b7ebc6b0c1
commit 528355c541
13 changed files with 111 additions and 3 deletions

View File

@ -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

View File

@ -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)?;

View File

@ -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),

View File

@ -356,6 +356,7 @@ symbols! {
concat_idents,
conservative_impl_trait,
console,
const_allocate,
const_compare_raw_pointers,
const_constructor,
const_eval_limit,

View File

@ -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)
}

View File

@ -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

View File

@ -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)]

View File

@ -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)
}

View File

@ -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);
}

View 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() {}

View File

@ -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`.

View File

@ -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() {}

View File

@ -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