From 528355c541b2f5d54d91a642355e39e01d93c75f Mon Sep 17 00:00:00 2001 From: Vishnunarayan K I Date: Tue, 1 Dec 2020 15:39:25 +0530 Subject: [PATCH] add const_allocate intrisic --- compiler/rustc_mir/src/interpret/intern.rs | 2 +- .../rustc_mir/src/interpret/intrinsics.rs | 18 +++++++++++++++-- compiler/rustc_mir/src/interpret/memory.rs | 4 ++++ compiler/rustc_span/src/symbol.rs | 1 + compiler/rustc_typeck/src/check/intrinsic.rs | 4 ++++ library/core/src/intrinsics.rs | 5 +++++ library/core/src/lib.rs | 1 + .../heap/alloc_intrinsic_nontransient.rs | 20 +++++++++++++++++++ .../heap/alloc_intrinsic_transient.rs | 20 +++++++++++++++++++ .../const-eval/heap/alloc_intrinsic_uninit.rs | 10 ++++++++++ .../heap/alloc_intrinsic_uninit.stderr | 11 ++++++++++ .../heap/alloc_intrinsic_untyped.rs | 10 ++++++++++ .../heap/alloc_intrinsic_untyped.stderr | 8 ++++++++ 13 files changed, 111 insertions(+), 3 deletions(-) create mode 100644 src/test/ui/consts/const-eval/heap/alloc_intrinsic_nontransient.rs create mode 100644 src/test/ui/consts/const-eval/heap/alloc_intrinsic_transient.rs create mode 100644 src/test/ui/consts/const-eval/heap/alloc_intrinsic_uninit.rs create mode 100644 src/test/ui/consts/const-eval/heap/alloc_intrinsic_uninit.stderr create mode 100644 src/test/ui/consts/const-eval/heap/alloc_intrinsic_untyped.rs create mode 100644 src/test/ui/consts/const-eval/heap/alloc_intrinsic_untyped.stderr diff --git a/compiler/rustc_mir/src/interpret/intern.rs b/compiler/rustc_mir/src/interpret/intern.rs index 413be427339..443ef072647 100644 --- a/compiler/rustc_mir/src/interpret/intern.rs +++ b/compiler/rustc_mir/src/interpret/intern.rs @@ -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 diff --git a/compiler/rustc_mir/src/interpret/intrinsics.rs b/compiler/rustc_mir/src/interpret/intrinsics.rs index f666a89ca56..953c04a1007 100644 --- a/compiler/rustc_mir/src/interpret/intrinsics.rs +++ b/compiler/rustc_mir/src/interpret/intrinsics.rs @@ -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)?; diff --git a/compiler/rustc_mir/src/interpret/memory.rs b/compiler/rustc_mir/src/interpret/memory.rs index f3e373813ca..ce64923727c 100644 --- a/compiler/rustc_mir/src/interpret/memory.rs +++ b/compiler/rustc_mir/src/interpret/memory.rs @@ -27,6 +27,8 @@ use crate::util::pretty; pub enum MemoryKind { /// 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 MayLeak for MemoryKind { 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 fmt::Display for MemoryKind { 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), diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index 523628b7058..91b87fdc482 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -356,6 +356,7 @@ symbols! { concat_idents, conservative_impl_trait, console, + const_allocate, const_compare_raw_pointers, const_constructor, const_eval_limit, diff --git a/compiler/rustc_typeck/src/check/intrinsic.rs b/compiler/rustc_typeck/src/check/intrinsic.rs index f40a250200e..e2712a30339 100644 --- a/compiler/rustc_typeck/src/check/intrinsic.rs +++ b/compiler/rustc_typeck/src/check/intrinsic.rs @@ -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) } diff --git a/library/core/src/intrinsics.rs b/library/core/src/intrinsics.rs index 1a588b314c4..72282a93b70 100644 --- a/library/core/src/intrinsics.rs +++ b/library/core/src/intrinsics.rs @@ -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(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 diff --git a/library/core/src/lib.rs b/library/core/src/lib.rs index e3b004be39a..bb76683e0fe 100644 --- a/library/core/src/lib.rs +++ b/library/core/src/lib.rs @@ -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)] diff --git a/src/test/ui/consts/const-eval/heap/alloc_intrinsic_nontransient.rs b/src/test/ui/consts/const-eval/heap/alloc_intrinsic_nontransient.rs new file mode 100644 index 00000000000..db650f8817f --- /dev/null +++ b/src/test/ui/consts/const-eval/heap/alloc_intrinsic_nontransient.rs @@ -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) +} diff --git a/src/test/ui/consts/const-eval/heap/alloc_intrinsic_transient.rs b/src/test/ui/consts/const-eval/heap/alloc_intrinsic_transient.rs new file mode 100644 index 00000000000..c55cd32d264 --- /dev/null +++ b/src/test/ui/consts/const-eval/heap/alloc_intrinsic_transient.rs @@ -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); +} diff --git a/src/test/ui/consts/const-eval/heap/alloc_intrinsic_uninit.rs b/src/test/ui/consts/const-eval/heap/alloc_intrinsic_uninit.rs new file mode 100644 index 00000000000..998b6cef84a --- /dev/null +++ b/src/test/ui/consts/const-eval/heap/alloc_intrinsic_uninit.rs @@ -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() {} diff --git a/src/test/ui/consts/const-eval/heap/alloc_intrinsic_uninit.stderr b/src/test/ui/consts/const-eval/heap/alloc_intrinsic_uninit.stderr new file mode 100644 index 00000000000..866f877f54d --- /dev/null +++ b/src/test/ui/consts/const-eval/heap/alloc_intrinsic_uninit.stderr @@ -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 ., 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`. diff --git a/src/test/ui/consts/const-eval/heap/alloc_intrinsic_untyped.rs b/src/test/ui/consts/const-eval/heap/alloc_intrinsic_untyped.rs new file mode 100644 index 00000000000..625f7670bcd --- /dev/null +++ b/src/test/ui/consts/const-eval/heap/alloc_intrinsic_untyped.rs @@ -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() {} diff --git a/src/test/ui/consts/const-eval/heap/alloc_intrinsic_untyped.stderr b/src/test/ui/consts/const-eval/heap/alloc_intrinsic_untyped.stderr new file mode 100644 index 00000000000..ee84f8e54f3 --- /dev/null +++ b/src/test/ui/consts/const-eval/heap/alloc_intrinsic_untyped.stderr @@ -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 +