Skip to content

Commit d015f0d

Browse files
committed
Auto merge of #79594 - vn-ki:const-eval-intrinsic, r=oli-obk
add const_allocate intrinsic r? `@oli-obk` fixes #75390
2 parents c7cff21 + bc6eb6f commit d015f0d

28 files changed

+424
-141
lines changed

compiler/rustc_mir/src/const_eval/machine.rs

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
use rustc_middle::mir;
22
use rustc_middle::ty::layout::HasTyCtxt;
3+
use rustc_middle::ty::InstanceDef;
34
use rustc_middle::ty::{self, Ty};
45
use std::borrow::Borrow;
56
use std::collections::hash_map::Entry;
@@ -12,6 +13,7 @@ use rustc_hir::def_id::DefId;
1213
use rustc_middle::mir::AssertMessage;
1314
use rustc_session::Limit;
1415
use rustc_span::symbol::{sym, Symbol};
16+
use rustc_target::abi::{Align, Size};
1517

1618
use crate::interpret::{
1719
self, compile_time_machine, AllocId, Allocation, Frame, GlobalId, ImmTy, InterpCx,
@@ -37,6 +39,14 @@ impl<'mir, 'tcx> InterpCx<'mir, 'tcx, CompileTimeInterpreter<'mir, 'tcx>> {
3739
if instance.def.requires_caller_location(self.tcx()) {
3840
return Ok(false);
3941
}
42+
// Only memoize instrinsics. This was added in #79594 while adding the `const_allocate` intrinsic.
43+
// We only memoize intrinsics because it would be unsound to memoize functions
44+
// which might interact with the heap.
45+
// Additionally, const_allocate intrinsic is impure and thus should not be memoized;
46+
// it will not be memoized because it has non-ZST args
47+
if !matches!(instance.def, InstanceDef::Intrinsic(_)) {
48+
return Ok(false);
49+
}
4050
// For the moment we only do this for functions which take no arguments
4151
// (or all arguments are ZSTs) so that we don't memoize too much.
4252
if args.iter().any(|a| !a.layout.is_zst()) {
@@ -295,6 +305,22 @@ impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for CompileTimeInterpreter<'mir,
295305
};
296306
ecx.write_scalar(Scalar::from_bool(cmp), dest)?;
297307
}
308+
sym::const_allocate => {
309+
let size = ecx.read_scalar(args[0])?.to_machine_usize(ecx)?;
310+
let align = ecx.read_scalar(args[1])?.to_machine_usize(ecx)?;
311+
312+
let align = match Align::from_bytes(align) {
313+
Ok(a) => a,
314+
Err(err) => throw_ub_format!("align has to be a power of 2, {}", err),
315+
};
316+
317+
let ptr = ecx.memory.allocate(
318+
Size::from_bytes(size as u64),
319+
align,
320+
interpret::MemoryKind::ConstHeap,
321+
);
322+
ecx.write_scalar(Scalar::Ptr(ptr), dest)?;
323+
}
298324
_ => {
299325
return Err(ConstEvalErrKind::NeedsRfc(format!(
300326
"calling intrinsic `{}`",

compiler/rustc_mir/src/interpret/intern.rs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -104,7 +104,10 @@ 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
108+
| MemoryKind::ConstHeap
109+
| MemoryKind::Vtable
110+
| MemoryKind::CallerLocation => {}
108111
}
109112
// Set allocation mutability as appropriate. This is used by LLVM to put things into
110113
// read-only memory, and also by Miri when evaluating other globals that

compiler/rustc_mir/src/interpret/memory.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,9 @@ 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+
/// FIXME: this variant should be in const_eval
32+
ConstHeap,
3033
/// Memory backing vtables. Error if ever deallocated.
3134
Vtable,
3235
/// Memory allocated by `caller_location` intrinsic. Error if ever deallocated.
@@ -40,6 +43,7 @@ impl<T: MayLeak> MayLeak for MemoryKind<T> {
4043
fn may_leak(self) -> bool {
4144
match self {
4245
MemoryKind::Stack => false,
46+
MemoryKind::ConstHeap => false,
4347
MemoryKind::Vtable => true,
4448
MemoryKind::CallerLocation => true,
4549
MemoryKind::Machine(k) => k.may_leak(),
@@ -51,6 +55,7 @@ impl<T: fmt::Display> fmt::Display for MemoryKind<T> {
5155
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
5256
match self {
5357
MemoryKind::Stack => write!(f, "stack variable"),
58+
MemoryKind::ConstHeap => write!(f, "heap allocation"),
5459
MemoryKind::Vtable => write!(f, "vtable"),
5560
MemoryKind::CallerLocation => write!(f, "caller location"),
5661
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 = "79597")]
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)]

src/test/ui/const-generics/const-argument-if-length.full.stderr

Lines changed: 2 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -11,12 +11,6 @@ LL | if std::mem::size_of::<T>() == 0 {
1111
LL | pub const fn size_of<T>() -> usize {
1212
| - required by this bound in `std::mem::size_of`
1313

14-
error[E0080]: evaluation of constant value failed
15-
--> $DIR/const-argument-if-length.rs:19:15
16-
|
17-
LL | pad: [u8; is_zst::<T>()],
18-
| ^^^^^^^^^^^^^ referenced constant has errors
19-
2014
error[E0277]: the size for values of type `T` cannot be known at compilation time
2115
--> $DIR/const-argument-if-length.rs:17:12
2216
|
@@ -36,7 +30,6 @@ help: the `Box` type always has a statically known size and allocates its conten
3630
LL | value: Box<T>,
3731
| ^^^^ ^
3832

39-
error: aborting due to 3 previous errors
33+
error: aborting due to 2 previous errors
4034

41-
Some errors have detailed explanations: E0080, E0277.
42-
For more information about an error, try `rustc --explain E0080`.
35+
For more information about this error, try `rustc --explain E0277`.

src/test/ui/const-generics/const-argument-if-length.rs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,6 @@ pub struct AtLeastByte<T: ?Sized> {
1818
//~^ ERROR the size for values of type `T` cannot be known at compilation time
1919
pad: [u8; is_zst::<T>()],
2020
//[min]~^ ERROR generic parameters may not be used in const operations
21-
//[full]~^^ ERROR evaluation of constant value failed
2221
}
2322

2423
fn main() {}

src/test/ui/consts/const-eval/erroneous-const.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,11 +9,11 @@ impl<T> PrintName<T> {
99

1010
const fn no_codegen<T>() {
1111
if false {
12-
let _ = PrintName::<T>::VOID; //~ERROR evaluation of constant value failed
12+
let _ = PrintName::<T>::VOID; //~ERROR could not evaluate static initializer
1313
}
1414
}
1515

16-
pub static FOO: () = no_codegen::<i32>(); //~ERROR could not evaluate static initializer
16+
pub static FOO: () = no_codegen::<i32>();
1717

1818
fn main() {
1919
FOO

0 commit comments

Comments
 (0)