Skip to content

Commit

Permalink
const_deallocate: Don't deallocate memory allocated in an another c…
Browse files Browse the repository at this point in the history
…onst. Does nothing at runtime.

`const_allocate`:  Returns a null pointer at runtime.
  • Loading branch information
lilasta committed Jan 26, 2022
1 parent aa6795e commit 29932db
Show file tree
Hide file tree
Showing 8 changed files with 69 additions and 11 deletions.
10 changes: 10 additions & 0 deletions compiler/rustc_codegen_ssa/src/mir/intrinsic.rs
Original file line number Diff line number Diff line change
Expand Up @@ -369,6 +369,16 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
}
}

sym::const_allocate => {
// returns a null pointer at runtime.
bx.const_null(bx.type_i8p())
}

sym::const_deallocate => {
// nop at runtime.
return;
}

// This requires that atomic intrinsics follow a specific naming pattern:
// "atomic_<operation>[_<ordering>]", and no ordering means SeqCst
name if name_str.starts_with("atomic_") => {
Expand Down
20 changes: 15 additions & 5 deletions compiler/rustc_const_eval/src/const_eval/machine.rs
Original file line number Diff line number Diff line change
Expand Up @@ -358,11 +358,21 @@ impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for CompileTimeInterpreter<'mir,
Err(err) => throw_ub_format!("align has to be a power of 2, {}", err),
};

ecx.memory.deallocate(
ptr,
Some((size, align)),
interpret::MemoryKind::Machine(MemoryKind::Heap),
)?;
// If an allocation is created in an another const,
// we don't deallocate it.
let (alloc_id, _, _) = ecx.memory.ptr_get_alloc(ptr)?;
let is_allocated_in_another_const = matches!(
ecx.tcx.get_global_alloc(alloc_id),
Some(interpret::GlobalAlloc::Memory(_))
);

if !is_allocated_in_another_const {
ecx.memory.deallocate(
ptr,
Some((size, align)),
interpret::MemoryKind::Machine(MemoryKind::Heap),
)?;
}
}
_ => {
return Err(ConstEvalErrKind::NeedsRfc(format!(
Expand Down
5 changes: 3 additions & 2 deletions library/core/src/intrinsics.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1914,12 +1914,13 @@ extern "rust-intrinsic" {
#[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.
/// Allocate at compile time.
/// Returns a null pointer at runtime.
#[rustc_const_unstable(feature = "const_heap", issue = "79597")]
pub fn const_allocate(size: usize, align: usize) -> *mut u8;

/// Deallocate a memory which allocated by `intrinsics::const_allocate` at compile time.
/// Should not be called at runtime.
/// Does nothing at runtime.
#[rustc_const_unstable(feature = "const_heap", issue = "79597")]
#[cfg(not(bootstrap))]
pub fn const_deallocate(ptr: *mut u8, size: usize, align: usize);
Expand Down
13 changes: 13 additions & 0 deletions library/core/tests/intrinsics.rs
Original file line number Diff line number Diff line change
Expand Up @@ -80,3 +80,16 @@ fn test_hints_in_const_contexts() {
assert!(42u32 == core::hint::black_box(42u32));
}
}

#[cfg(not(bootstrap))]
#[test]
fn test_const_dealocate_at_runtime() {
use core::intrinsics::const_deallocate;
const X: &u32 = &42u32;
let x = &0u32;
unsafe {
const_deallocate(X as *const _ as *mut u8, 4, 4); // nop
const_deallocate(x as *const _ as *mut u8, 4, 4); // nop
const_deallocate(core::ptr::null_mut(), 1, 1); // nop
}
}
1 change: 1 addition & 0 deletions library/core/tests/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
#![feature(const_bool_to_option)]
#![feature(const_cell_into_inner)]
#![feature(const_convert)]
#![feature(const_heap)]
#![feature(const_maybe_uninit_as_mut_ptr)]
#![feature(const_maybe_uninit_assume_init)]
#![feature(const_maybe_uninit_assume_init_read)]
Expand Down
3 changes: 1 addition & 2 deletions src/test/ui/consts/const-eval/heap/alloc_intrinsic_errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,10 @@ use std::intrinsics;
const FOO: i32 = foo();
const fn foo() -> i32 {
unsafe {
let _ = intrinsics::const_allocate(4, 3) as * mut i32;
let _ = intrinsics::const_allocate(4, 3) as *mut i32;
//~^ error: evaluation of constant value failed
}
1

}

fn main() {}
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ error[E0080]: evaluation of constant value failed
LL | const FOO: i32 = foo();
| ----- inside `FOO` at $DIR/alloc_intrinsic_errors.rs:6:18
...
LL | let _ = intrinsics::const_allocate(4, 3) as * mut i32;
LL | let _ = intrinsics::const_allocate(4, 3) as *mut i32;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
| |
| align has to be a power of 2, `3` is not a power of 2
Expand Down
26 changes: 25 additions & 1 deletion src/test/ui/consts/const-eval/heap/dealloc_intrinsic.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
// run-pass
#![feature(core_intrinsics)]
#![feature(const_heap)]
#![feature(const_mut_refs)]

use std::intrinsics;

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

fn main() {}
const Y: &u32 = unsafe {
let ptr = intrinsics::const_allocate(4, 4) as *mut u32;
*ptr = 42;
&*ptr
};

const Z: &u32 = &42;

const _Z: () = unsafe {
let ptr1 = Y as *const _ as *mut u8;
intrinsics::const_deallocate(ptr1, 4, 4); // nop
intrinsics::const_deallocate(ptr1, 2, 4); // nop
intrinsics::const_deallocate(ptr1, 4, 2); // nop

let ptr2 = Z as *const _ as *mut u8;
intrinsics::const_deallocate(ptr2, 4, 4); // nop
intrinsics::const_deallocate(ptr2, 2, 4); // nop
intrinsics::const_deallocate(ptr2, 4, 2); // nop
};

fn main() {
assert_eq!(*Y, 42);
assert_eq!(*Z, 42);
}

0 comments on commit 29932db

Please sign in to comment.