Skip to content

Commit 528355c

Browse files
committed
add const_allocate intrisic
1 parent b7ebc6b commit 528355c

File tree

13 files changed

+111
-3
lines changed

13 files changed

+111
-3
lines changed

compiler/rustc_mir/src/interpret/intern.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -104,7 +104,7 @@ fn intern_shallow<'rt, 'mir, 'tcx, M: CompileTimeMachine<'mir, 'tcx>>(
104104
// This match is just a canary for future changes to `MemoryKind`, which most likely need
105105
// changes in this function.
106106
match kind {
107-
MemoryKind::Stack | MemoryKind::Vtable | MemoryKind::CallerLocation => {}
107+
MemoryKind::Stack | MemoryKind::Heap | MemoryKind::Vtable | MemoryKind::CallerLocation => {}
108108
}
109109
// Set allocation mutability as appropriate. This is used by LLVM to put things into
110110
// read-only memory, and also by Miri when evaluating other globals that

compiler/rustc_mir/src/interpret/intrinsics.rs

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,10 +14,11 @@ use rustc_middle::ty;
1414
use rustc_middle::ty::subst::SubstsRef;
1515
use rustc_middle::ty::{Ty, TyCtxt};
1616
use rustc_span::symbol::{sym, Symbol};
17-
use rustc_target::abi::{Abi, LayoutOf as _, Primitive, Size};
17+
use rustc_target::abi::{Abi, Align, LayoutOf as _, Primitive, Size};
1818

1919
use super::{
20-
util::ensure_monomorphic_enough, CheckInAllocMsg, ImmTy, InterpCx, Machine, OpTy, PlaceTy,
20+
util::ensure_monomorphic_enough, CheckInAllocMsg, ImmTy, InterpCx, Machine, MemoryKind, OpTy,
21+
PlaceTy,
2122
};
2223

2324
mod caller_location;
@@ -337,6 +338,19 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
337338
let result = Scalar::from_uint(truncated_bits, layout.size);
338339
self.write_scalar(result, dest)?;
339340
}
341+
sym::const_allocate => {
342+
let size = self.read_scalar(args[0])?.to_machine_usize(self)?;
343+
let align = self.read_scalar(args[1])?.to_machine_usize(self)?;
344+
345+
let align = match Align::from_bytes(align) {
346+
Ok(a) => a,
347+
Err(err) => bug!("align has to power of 2, {}", err),
348+
};
349+
350+
let ptr =
351+
self.memory.allocate(Size::from_bytes(size as u64), align, MemoryKind::Heap);
352+
self.write_scalar(Scalar::Ptr(ptr), dest)?;
353+
}
340354
sym::offset => {
341355
let ptr = self.read_scalar(args[0])?.check_init()?;
342356
let offset_count = self.read_scalar(args[1])?.to_machine_isize(self)?;

compiler/rustc_mir/src/interpret/memory.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,8 @@ use crate::util::pretty;
2727
pub enum MemoryKind<T> {
2828
/// Stack memory. Error if deallocated except during a stack pop.
2929
Stack,
30+
/// Heap memory.
31+
Heap,
3032
/// Memory backing vtables. Error if ever deallocated.
3133
Vtable,
3234
/// Memory allocated by `caller_location` intrinsic. Error if ever deallocated.
@@ -40,6 +42,7 @@ impl<T: MayLeak> MayLeak for MemoryKind<T> {
4042
fn may_leak(self) -> bool {
4143
match self {
4244
MemoryKind::Stack => false,
45+
MemoryKind::Heap => true,
4346
MemoryKind::Vtable => true,
4447
MemoryKind::CallerLocation => true,
4548
MemoryKind::Machine(k) => k.may_leak(),
@@ -51,6 +54,7 @@ impl<T: fmt::Display> fmt::Display for MemoryKind<T> {
5154
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
5255
match self {
5356
MemoryKind::Stack => write!(f, "stack variable"),
57+
MemoryKind::Heap => write!(f, "heap variable"),
5458
MemoryKind::Vtable => write!(f, "vtable"),
5559
MemoryKind::CallerLocation => write!(f, "caller location"),
5660
MemoryKind::Machine(m) => write!(f, "{}", m),

compiler/rustc_span/src/symbol.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -356,6 +356,7 @@ symbols! {
356356
concat_idents,
357357
conservative_impl_trait,
358358
console,
359+
const_allocate,
359360
const_compare_raw_pointers,
360361
const_constructor,
361362
const_eval_limit,

compiler/rustc_typeck/src/check/intrinsic.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -286,6 +286,10 @@ pub fn check_intrinsic_type(tcx: TyCtxt<'_>, it: &hir::ForeignItem<'_>) {
286286
(1, vec![tcx.mk_imm_ptr(param(0)), tcx.mk_imm_ptr(param(0))], tcx.types.bool)
287287
}
288288

289+
sym::const_allocate => {
290+
(0, vec![tcx.types.usize, tcx.types.usize], tcx.mk_mut_ptr(tcx.types.u8))
291+
}
292+
289293
sym::ptr_offset_from => {
290294
(1, vec![tcx.mk_imm_ptr(param(0)), tcx.mk_imm_ptr(param(0))], tcx.types.isize)
291295
}

library/core/src/intrinsics.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1732,6 +1732,11 @@ extern "rust-intrinsic" {
17321732
/// See documentation of `<*const T>::guaranteed_ne` for details.
17331733
#[rustc_const_unstable(feature = "const_raw_ptr_comparison", issue = "53020")]
17341734
pub fn ptr_guaranteed_ne<T>(ptr: *const T, other: *const T) -> bool;
1735+
1736+
/// Allocate at compile time. Should not be called at runtime.
1737+
#[rustc_const_unstable(feature = "const_heap", issue = "none")]
1738+
#[cfg(not(bootstrap))]
1739+
pub fn const_allocate(size: usize, align: usize) -> *mut u8;
17351740
}
17361741

17371742
// Some functions are defined here because they accidentally got made

library/core/src/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,7 @@
6868
#![feature(arbitrary_self_types)]
6969
#![feature(asm)]
7070
#![feature(cfg_target_has_atomic)]
71+
#![cfg_attr(not(bootstrap), feature(const_heap))]
7172
#![feature(const_alloc_layout)]
7273
#![feature(const_discriminant)]
7374
#![feature(const_cell_into_inner)]
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
// run-pass
2+
#![feature(core_intrinsics)]
3+
#![feature(const_heap)]
4+
#![feature(const_raw_ptr_deref)]
5+
#![feature(const_mut_refs)]
6+
use std::intrinsics;
7+
8+
const FOO: *const i32 = foo();
9+
10+
const fn foo() -> &'static i32 {
11+
let t = unsafe {
12+
let i = intrinsics::const_allocate(4, 4) as * mut i32;
13+
*i = 20;
14+
i
15+
};
16+
unsafe { &*t }
17+
}
18+
fn main() {
19+
assert_eq!(unsafe { *FOO }, 20)
20+
}
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
// run-pass
2+
#![feature(core_intrinsics)]
3+
#![feature(const_heap)]
4+
#![feature(const_raw_ptr_deref)]
5+
#![feature(const_mut_refs)]
6+
use std::intrinsics;
7+
8+
const FOO: i32 = foo();
9+
10+
const fn foo() -> i32 {
11+
let t = unsafe {
12+
let i = intrinsics::const_allocate(4, 4) as * mut i32;
13+
*i = 20;
14+
i
15+
};
16+
unsafe { *t }
17+
}
18+
fn main() {
19+
assert_eq!(FOO, 20);
20+
}
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
// compile-test
2+
#![feature(core_intrinsics)]
3+
#![feature(const_heap)]
4+
#![feature(const_raw_ptr_deref)]
5+
#![feature(const_mut_refs)]
6+
use std::intrinsics;
7+
8+
const BAR: &i32 = unsafe { &*(intrinsics::const_allocate(4, 4) as *mut i32) };
9+
//~^ error: it is undefined behavior to use this value
10+
fn main() {}
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
error[E0080]: it is undefined behavior to use this value
2+
--> $DIR/alloc_intrinsic_uninit.rs:8:1
3+
|
4+
LL | const BAR: &i32 = unsafe { &*(intrinsics::const_allocate(4, 4) as *mut i32) };
5+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered uninitialized bytes at .<deref>, but expected initialized plain (non-pointer) bytes
6+
|
7+
= 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.
8+
9+
error: aborting due to previous error
10+
11+
For more information about this error, try `rustc --explain E0080`.
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
#![feature(core_intrinsics)]
2+
#![feature(const_heap)]
3+
#![feature(const_raw_ptr_deref)]
4+
#![feature(const_mut_refs)]
5+
use std::intrinsics;
6+
7+
const BAR: *mut i32 = unsafe { intrinsics::const_allocate(4, 4) as *mut i32};
8+
//~^ error: untyped pointers are not allowed in constant
9+
10+
fn main() {}
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
error: untyped pointers are not allowed in constant
2+
--> $DIR/alloc_intrinsic_untyped.rs:7:1
3+
|
4+
LL | const BAR: *mut i32 = unsafe { intrinsics::const_allocate(4, 4) as *mut i32};
5+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
6+
7+
error: aborting due to previous error
8+

0 commit comments

Comments
 (0)