Skip to content

Commit 29932db

Browse files
committed
const_deallocate: Don't deallocate memory allocated in an another const. Does nothing at runtime.
`const_allocate`: Returns a null pointer at runtime.
1 parent aa6795e commit 29932db

File tree

8 files changed

+69
-11
lines changed

8 files changed

+69
-11
lines changed

Diff for: compiler/rustc_codegen_ssa/src/mir/intrinsic.rs

+10
Original file line numberDiff line numberDiff line change
@@ -369,6 +369,16 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
369369
}
370370
}
371371

372+
sym::const_allocate => {
373+
// returns a null pointer at runtime.
374+
bx.const_null(bx.type_i8p())
375+
}
376+
377+
sym::const_deallocate => {
378+
// nop at runtime.
379+
return;
380+
}
381+
372382
// This requires that atomic intrinsics follow a specific naming pattern:
373383
// "atomic_<operation>[_<ordering>]", and no ordering means SeqCst
374384
name if name_str.starts_with("atomic_") => {

Diff for: compiler/rustc_const_eval/src/const_eval/machine.rs

+15-5
Original file line numberDiff line numberDiff line change
@@ -358,11 +358,21 @@ impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for CompileTimeInterpreter<'mir,
358358
Err(err) => throw_ub_format!("align has to be a power of 2, {}", err),
359359
};
360360

361-
ecx.memory.deallocate(
362-
ptr,
363-
Some((size, align)),
364-
interpret::MemoryKind::Machine(MemoryKind::Heap),
365-
)?;
361+
// If an allocation is created in an another const,
362+
// we don't deallocate it.
363+
let (alloc_id, _, _) = ecx.memory.ptr_get_alloc(ptr)?;
364+
let is_allocated_in_another_const = matches!(
365+
ecx.tcx.get_global_alloc(alloc_id),
366+
Some(interpret::GlobalAlloc::Memory(_))
367+
);
368+
369+
if !is_allocated_in_another_const {
370+
ecx.memory.deallocate(
371+
ptr,
372+
Some((size, align)),
373+
interpret::MemoryKind::Machine(MemoryKind::Heap),
374+
)?;
375+
}
366376
}
367377
_ => {
368378
return Err(ConstEvalErrKind::NeedsRfc(format!(

Diff for: library/core/src/intrinsics.rs

+3-2
Original file line numberDiff line numberDiff line change
@@ -1914,12 +1914,13 @@ extern "rust-intrinsic" {
19141914
#[rustc_const_unstable(feature = "const_raw_ptr_comparison", issue = "53020")]
19151915
pub fn ptr_guaranteed_ne<T>(ptr: *const T, other: *const T) -> bool;
19161916

1917-
/// Allocate at compile time. Should not be called at runtime.
1917+
/// Allocate at compile time.
1918+
/// Returns a null pointer at runtime.
19181919
#[rustc_const_unstable(feature = "const_heap", issue = "79597")]
19191920
pub fn const_allocate(size: usize, align: usize) -> *mut u8;
19201921

19211922
/// Deallocate a memory which allocated by `intrinsics::const_allocate` at compile time.
1922-
/// Should not be called at runtime.
1923+
/// Does nothing at runtime.
19231924
#[rustc_const_unstable(feature = "const_heap", issue = "79597")]
19241925
#[cfg(not(bootstrap))]
19251926
pub fn const_deallocate(ptr: *mut u8, size: usize, align: usize);

Diff for: library/core/tests/intrinsics.rs

+13
Original file line numberDiff line numberDiff line change
@@ -80,3 +80,16 @@ fn test_hints_in_const_contexts() {
8080
assert!(42u32 == core::hint::black_box(42u32));
8181
}
8282
}
83+
84+
#[cfg(not(bootstrap))]
85+
#[test]
86+
fn test_const_dealocate_at_runtime() {
87+
use core::intrinsics::const_deallocate;
88+
const X: &u32 = &42u32;
89+
let x = &0u32;
90+
unsafe {
91+
const_deallocate(X as *const _ as *mut u8, 4, 4); // nop
92+
const_deallocate(x as *const _ as *mut u8, 4, 4); // nop
93+
const_deallocate(core::ptr::null_mut(), 1, 1); // nop
94+
}
95+
}

Diff for: library/core/tests/lib.rs

+1
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
#![feature(const_bool_to_option)]
1414
#![feature(const_cell_into_inner)]
1515
#![feature(const_convert)]
16+
#![feature(const_heap)]
1617
#![feature(const_maybe_uninit_as_mut_ptr)]
1718
#![feature(const_maybe_uninit_assume_init)]
1819
#![feature(const_maybe_uninit_assume_init_read)]

Diff for: src/test/ui/consts/const-eval/heap/alloc_intrinsic_errors.rs

+1-2
Original file line numberDiff line numberDiff line change
@@ -6,11 +6,10 @@ use std::intrinsics;
66
const FOO: i32 = foo();
77
const fn foo() -> i32 {
88
unsafe {
9-
let _ = intrinsics::const_allocate(4, 3) as * mut i32;
9+
let _ = intrinsics::const_allocate(4, 3) as *mut i32;
1010
//~^ error: evaluation of constant value failed
1111
}
1212
1
13-
1413
}
1514

1615
fn main() {}

Diff for: src/test/ui/consts/const-eval/heap/alloc_intrinsic_errors.stderr

+1-1
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ error[E0080]: evaluation of constant value failed
44
LL | const FOO: i32 = foo();
55
| ----- inside `FOO` at $DIR/alloc_intrinsic_errors.rs:6:18
66
...
7-
LL | let _ = intrinsics::const_allocate(4, 3) as * mut i32;
7+
LL | let _ = intrinsics::const_allocate(4, 3) as *mut i32;
88
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
99
| |
1010
| align has to be a power of 2, `3` is not a power of 2
+25-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
// run-pass
22
#![feature(core_intrinsics)]
33
#![feature(const_heap)]
4+
#![feature(const_mut_refs)]
45

56
use std::intrinsics;
67

@@ -9,4 +10,27 @@ const _X: () = unsafe {
910
intrinsics::const_deallocate(ptr, 4, 4);
1011
};
1112

12-
fn main() {}
13+
const Y: &u32 = unsafe {
14+
let ptr = intrinsics::const_allocate(4, 4) as *mut u32;
15+
*ptr = 42;
16+
&*ptr
17+
};
18+
19+
const Z: &u32 = &42;
20+
21+
const _Z: () = unsafe {
22+
let ptr1 = Y as *const _ as *mut u8;
23+
intrinsics::const_deallocate(ptr1, 4, 4); // nop
24+
intrinsics::const_deallocate(ptr1, 2, 4); // nop
25+
intrinsics::const_deallocate(ptr1, 4, 2); // nop
26+
27+
let ptr2 = Z as *const _ as *mut u8;
28+
intrinsics::const_deallocate(ptr2, 4, 4); // nop
29+
intrinsics::const_deallocate(ptr2, 2, 4); // nop
30+
intrinsics::const_deallocate(ptr2, 4, 2); // nop
31+
};
32+
33+
fn main() {
34+
assert_eq!(*Y, 42);
35+
assert_eq!(*Z, 42);
36+
}

0 commit comments

Comments
 (0)