Skip to content

Commit 74b8cf7

Browse files
committed
Add a layout_of_val intrinsic to get the Layout directly
1 parent 3c9faa0 commit 74b8cf7

10 files changed

Lines changed: 150 additions & 185 deletions

compiler/rustc_hir_analysis/src/check/intrinsic.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -296,6 +296,9 @@ pub(crate) fn check_intrinsic_type(
296296
sym::size_of_val | sym::align_of_val => {
297297
(1, 0, vec![Ty::new_imm_ptr(tcx, param(0))], tcx.types.usize)
298298
}
299+
sym::layout_of_val => {
300+
(1, 0, vec![Ty::new_imm_ptr(tcx, param(0))], tcx.ty_alloc_layout(span))
301+
}
299302
sym::offset_of => (1, 0, vec![tcx.types.u32, tcx.types.u32], tcx.types.usize),
300303
sym::rustc_peek => (1, 0, vec![param(0)], param(0)),
301304
sym::caller_location => (0, 0, vec![], tcx.caller_location_ty()),

compiler/rustc_middle/src/ty/context.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1079,6 +1079,12 @@ impl<'tcx> TyCtxt<'tcx> {
10791079
self.type_of(ordering_enum).no_bound_vars().unwrap()
10801080
}
10811081

1082+
/// Gets a `Ty` representing the [`LangItem::Alignment`]
1083+
pub fn ty_alloc_layout(self, span: Span) -> Ty<'tcx> {
1084+
let layout_did = self.require_lang_item(hir::LangItem::AllocLayout, span);
1085+
self.type_of(layout_did).no_bound_vars().unwrap()
1086+
}
1087+
10821088
/// Obtain the given diagnostic item's `DefId`. Use `is_diagnostic_item` if you just want to
10831089
/// compare against another `DefId`, since `is_diagnostic_item` is cheaper.
10841090
pub fn get_diagnostic_item(self, name: Symbol) -> Option<DefId> {

compiler/rustc_span/src/symbol.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1347,6 +1347,7 @@ symbols! {
13471347
large_assignments,
13481348
last,
13491349
lateout,
1350+
layout_of_val,
13501351
lazy_normalization_consts,
13511352
lazy_type_alias,
13521353
le,

library/core/src/alloc/layout.rs

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
// Your performance intuition is useless. Run perf.
66

77
use crate::error::Error;
8-
use crate::intrinsics::{unchecked_add, unchecked_mul, unchecked_sub};
8+
use crate::intrinsics::{self, unchecked_add, unchecked_mul, unchecked_sub};
99
use crate::mem::SizedTypeProperties;
1010
use crate::ptr::{Alignment, NonNull};
1111
use crate::{assert_unsafe_precondition, fmt, mem};
@@ -250,11 +250,9 @@ impl Layout {
250250
#[unstable(feature = "layout_for_ptr", issue = "69835")]
251251
#[must_use]
252252
#[inline]
253-
pub const unsafe fn for_value_raw<T: ?Sized>(t: *const T) -> Self {
253+
pub const unsafe fn for_value_raw<T: ?Sized>(ptr: *const T) -> Self {
254254
// SAFETY: we pass along the prerequisites of these functions to the caller
255-
let (size, alignment) = unsafe { (mem::size_of_val_raw(t), Alignment::of_val_raw(t)) };
256-
// SAFETY: see rationale in `new` for why this is using the unsafe variant
257-
unsafe { Layout::from_size_alignment_unchecked(size, alignment) }
255+
unsafe { intrinsics::layout_of_val(ptr) }
258256
}
259257

260258
/// Creates a `NonNull` that is dangling, but well-aligned for this Layout.

library/core/src/intrinsics/mod.rs

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@
5353
issue = "none"
5454
)]
5555

56+
use crate::alloc::Layout;
5657
use crate::ffi::va_list::{VaArgSafe, VaList};
5758
use crate::marker::{ConstParamTy, DiscriminantKind, PointeeSized, Tuple};
5859
use crate::{mem, ptr};
@@ -2864,6 +2865,26 @@ pub const unsafe fn size_of_val<T: ?Sized>(ptr: *const T) -> usize;
28642865
#[rustc_intrinsic_const_stable_indirect]
28652866
pub const unsafe fn align_of_val<T: ?Sized>(ptr: *const T) -> usize;
28662867

2868+
/// The size and alignment of the referenced value in bytes.
2869+
///
2870+
/// The stabilized version of this intrinsic is [`Layout::for_value_raw`].
2871+
///
2872+
/// # Safety
2873+
///
2874+
/// See [`Layout::for_value_raw`] for safety conditions.
2875+
#[rustc_nounwind]
2876+
#[unstable(feature = "core_intrinsics", issue = "none")]
2877+
#[rustc_intrinsic]
2878+
// This adds no semantics or UB atop just calling `size_of_val`+`align_of_val`.
2879+
#[miri::intrinsic_fallback_is_spec]
2880+
pub const unsafe fn layout_of_val<T: ?Sized>(ptr: *const T) -> Layout {
2881+
// SAFETY: we pass along the prerequisites of these functions to the caller
2882+
let (size, align) = unsafe { (size_of_val(ptr), align_of_val(ptr)) };
2883+
// SAFETY: The size and alignment of a valid allocation (or type)
2884+
// always meet the requirements of `Layout`.
2885+
unsafe { Layout::from_size_align_unchecked(size, align) }
2886+
}
2887+
28672888
/// Compute the type information of a concrete type.
28682889
/// It can only be called at compile time, the backends do
28692890
/// not implement it.

tests/mir-opt/pre-codegen/drop_boxed_slice.generic_in_place.PreCodegen.after.32bit.panic-abort.mir

Lines changed: 28 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -8,33 +8,36 @@ fn generic_in_place(_1: *mut Box<[T]>) -> () {
88
let _2: std::ptr::NonNull<[T]>;
99
let mut _3: *mut [T];
1010
let mut _4: *const [T];
11+
let mut _6: usize;
1112
let _9: ();
1213
scope 3 {
14+
let _5: std::alloc::Layout;
1315
scope 4 {
14-
scope 17 (inlined Layout::size) {
16+
scope 8 (inlined Layout::size) {
1517
}
16-
scope 18 (inlined std::ptr::Unique::<[T]>::cast::<u8>) {
17-
scope 19 (inlined NonNull::<[T]>::cast::<u8>) {
18-
scope 20 (inlined NonNull::<[T]>::as_ptr) {
18+
scope 9 (inlined std::ptr::Unique::<[T]>::cast::<u8>) {
19+
scope 10 (inlined NonNull::<[T]>::cast::<u8>) {
20+
scope 11 (inlined NonNull::<[T]>::as_ptr) {
1921
}
2022
}
2123
}
22-
scope 21 (inlined <NonNull<u8> as From<std::ptr::Unique<u8>>>::from) {
23-
scope 22 (inlined std::ptr::Unique::<u8>::as_non_null_ptr) {
24+
scope 12 (inlined <NonNull<u8> as From<std::ptr::Unique<u8>>>::from) {
25+
scope 13 (inlined std::ptr::Unique::<u8>::as_non_null_ptr) {
2426
}
2527
}
26-
scope 23 (inlined <std::alloc::Global as Allocator>::deallocate) {
27-
scope 24 (inlined std::alloc::Global::deallocate_impl) {
28-
scope 25 (inlined std::alloc::Global::deallocate_impl_runtime) {
29-
let mut _8: *mut u8;
30-
scope 26 (inlined Layout::size) {
28+
scope 14 (inlined <std::alloc::Global as Allocator>::deallocate) {
29+
scope 15 (inlined std::alloc::Global::deallocate_impl) {
30+
scope 16 (inlined std::alloc::Global::deallocate_impl_runtime) {
31+
let mut _7: *mut u8;
32+
scope 17 (inlined Layout::size) {
3133
}
32-
scope 27 (inlined NonNull::<u8>::as_ptr) {
34+
scope 18 (inlined NonNull::<u8>::as_ptr) {
3335
}
34-
scope 28 (inlined std::alloc::dealloc) {
35-
scope 29 (inlined Layout::size) {
36+
scope 19 (inlined std::alloc::dealloc) {
37+
let mut _8: std::ptr::Alignment;
38+
scope 20 (inlined Layout::size) {
3639
}
37-
scope 30 (inlined Layout::alignment) {
40+
scope 21 (inlined Layout::alignment) {
3841
}
3942
}
4043
}
@@ -46,63 +49,44 @@ fn generic_in_place(_1: *mut Box<[T]>) -> () {
4649
}
4750
}
4851
scope 7 (inlined Layout::for_value_raw::<[T]>) {
49-
let mut _5: usize;
50-
let mut _7: std::ptr::Alignment;
51-
scope 8 {
52-
scope 16 (inlined #[track_caller] Layout::from_size_alignment_unchecked) {
53-
}
54-
}
55-
scope 9 (inlined size_of_val_raw::<[T]>) {
56-
}
57-
scope 10 (inlined std::ptr::Alignment::of_val_raw::<[T]>) {
58-
let _6: usize;
59-
scope 11 {
60-
scope 13 (inlined #[track_caller] std::ptr::Alignment::new_unchecked) {
61-
scope 14 (inlined core::ub_checks::check_language_ub) {
62-
scope 15 (inlined core::ub_checks::check_language_ub::runtime) {
63-
}
64-
}
65-
}
66-
}
67-
scope 12 (inlined align_of_val_raw::<[T]>) {
68-
}
69-
}
7052
}
7153
}
7254
}
7355
}
7456

7557
bb0: {
58+
StorageLive(_5);
7659
StorageLive(_2);
7760
_2 = copy (((*_1).0: std::ptr::Unique<[T]>).0: std::ptr::NonNull<[T]>);
7861
StorageLive(_4);
7962
_3 = copy _2 as *mut [T] (Transmute);
8063
_4 = copy _2 as *const [T] (Transmute);
81-
_5 = std::intrinsics::size_of_val::<[T]>(move _4) -> [return: bb1, unwind unreachable];
64+
_5 = layout_of_val::<[T]>(move _4) -> [return: bb1, unwind unreachable];
8265
}
8366

8467
bb1: {
85-
StorageLive(_6);
86-
_6 = const <T as std::mem::SizedTypeProperties>::ALIGN;
87-
_7 = copy _6 as std::ptr::Alignment (Transmute);
88-
StorageDead(_6);
8968
StorageDead(_4);
90-
switchInt(copy _5) -> [0: bb4, otherwise: bb2];
69+
_6 = copy (_5.0: usize);
70+
switchInt(copy _6) -> [0: bb4, otherwise: bb2];
9171
}
9272

9373
bb2: {
74+
StorageLive(_7);
75+
_7 = copy _3 as *mut u8 (PtrToPtr);
9476
StorageLive(_8);
95-
_8 = copy _3 as *mut u8 (PtrToPtr);
96-
_9 = alloc::alloc::__rust_dealloc(move _8, move _5, move _7) -> [return: bb3, unwind unreachable];
77+
_8 = copy (_5.1: std::ptr::Alignment);
78+
_9 = alloc::alloc::__rust_dealloc(move _7, move _6, move _8) -> [return: bb3, unwind unreachable];
9779
}
9880

9981
bb3: {
10082
StorageDead(_8);
83+
StorageDead(_7);
10184
goto -> bb4;
10285
}
10386

10487
bb4: {
10588
StorageDead(_2);
89+
StorageDead(_5);
10690
return;
10791
}
10892
}

tests/mir-opt/pre-codegen/drop_boxed_slice.generic_in_place.PreCodegen.after.32bit.panic-unwind.mir

Lines changed: 28 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -8,33 +8,36 @@ fn generic_in_place(_1: *mut Box<[T]>) -> () {
88
let _2: std::ptr::NonNull<[T]>;
99
let mut _3: *mut [T];
1010
let mut _4: *const [T];
11+
let mut _6: usize;
1112
let _9: ();
1213
scope 3 {
14+
let _5: std::alloc::Layout;
1315
scope 4 {
14-
scope 17 (inlined Layout::size) {
16+
scope 8 (inlined Layout::size) {
1517
}
16-
scope 18 (inlined std::ptr::Unique::<[T]>::cast::<u8>) {
17-
scope 19 (inlined NonNull::<[T]>::cast::<u8>) {
18-
scope 20 (inlined NonNull::<[T]>::as_ptr) {
18+
scope 9 (inlined std::ptr::Unique::<[T]>::cast::<u8>) {
19+
scope 10 (inlined NonNull::<[T]>::cast::<u8>) {
20+
scope 11 (inlined NonNull::<[T]>::as_ptr) {
1921
}
2022
}
2123
}
22-
scope 21 (inlined <NonNull<u8> as From<std::ptr::Unique<u8>>>::from) {
23-
scope 22 (inlined std::ptr::Unique::<u8>::as_non_null_ptr) {
24+
scope 12 (inlined <NonNull<u8> as From<std::ptr::Unique<u8>>>::from) {
25+
scope 13 (inlined std::ptr::Unique::<u8>::as_non_null_ptr) {
2426
}
2527
}
26-
scope 23 (inlined <std::alloc::Global as Allocator>::deallocate) {
27-
scope 24 (inlined std::alloc::Global::deallocate_impl) {
28-
scope 25 (inlined std::alloc::Global::deallocate_impl_runtime) {
29-
let mut _8: *mut u8;
30-
scope 26 (inlined Layout::size) {
28+
scope 14 (inlined <std::alloc::Global as Allocator>::deallocate) {
29+
scope 15 (inlined std::alloc::Global::deallocate_impl) {
30+
scope 16 (inlined std::alloc::Global::deallocate_impl_runtime) {
31+
let mut _7: *mut u8;
32+
scope 17 (inlined Layout::size) {
3133
}
32-
scope 27 (inlined NonNull::<u8>::as_ptr) {
34+
scope 18 (inlined NonNull::<u8>::as_ptr) {
3335
}
34-
scope 28 (inlined std::alloc::dealloc) {
35-
scope 29 (inlined Layout::size) {
36+
scope 19 (inlined std::alloc::dealloc) {
37+
let mut _8: std::ptr::Alignment;
38+
scope 20 (inlined Layout::size) {
3639
}
37-
scope 30 (inlined Layout::alignment) {
40+
scope 21 (inlined Layout::alignment) {
3841
}
3942
}
4043
}
@@ -46,63 +49,44 @@ fn generic_in_place(_1: *mut Box<[T]>) -> () {
4649
}
4750
}
4851
scope 7 (inlined Layout::for_value_raw::<[T]>) {
49-
let mut _5: usize;
50-
let mut _7: std::ptr::Alignment;
51-
scope 8 {
52-
scope 16 (inlined #[track_caller] Layout::from_size_alignment_unchecked) {
53-
}
54-
}
55-
scope 9 (inlined size_of_val_raw::<[T]>) {
56-
}
57-
scope 10 (inlined std::ptr::Alignment::of_val_raw::<[T]>) {
58-
let _6: usize;
59-
scope 11 {
60-
scope 13 (inlined #[track_caller] std::ptr::Alignment::new_unchecked) {
61-
scope 14 (inlined core::ub_checks::check_language_ub) {
62-
scope 15 (inlined core::ub_checks::check_language_ub::runtime) {
63-
}
64-
}
65-
}
66-
}
67-
scope 12 (inlined align_of_val_raw::<[T]>) {
68-
}
69-
}
7052
}
7153
}
7254
}
7355
}
7456

7557
bb0: {
58+
StorageLive(_5);
7659
StorageLive(_2);
7760
_2 = copy (((*_1).0: std::ptr::Unique<[T]>).0: std::ptr::NonNull<[T]>);
7861
StorageLive(_4);
7962
_3 = copy _2 as *mut [T] (Transmute);
8063
_4 = copy _2 as *const [T] (Transmute);
81-
_5 = std::intrinsics::size_of_val::<[T]>(move _4) -> [return: bb1, unwind unreachable];
64+
_5 = layout_of_val::<[T]>(move _4) -> [return: bb1, unwind unreachable];
8265
}
8366

8467
bb1: {
85-
StorageLive(_6);
86-
_6 = const <T as std::mem::SizedTypeProperties>::ALIGN;
87-
_7 = copy _6 as std::ptr::Alignment (Transmute);
88-
StorageDead(_6);
8968
StorageDead(_4);
90-
switchInt(copy _5) -> [0: bb4, otherwise: bb2];
69+
_6 = copy (_5.0: usize);
70+
switchInt(copy _6) -> [0: bb4, otherwise: bb2];
9171
}
9272

9373
bb2: {
74+
StorageLive(_7);
75+
_7 = copy _3 as *mut u8 (PtrToPtr);
9476
StorageLive(_8);
95-
_8 = copy _3 as *mut u8 (PtrToPtr);
96-
_9 = alloc::alloc::__rust_dealloc(move _8, move _5, move _7) -> [return: bb3, unwind unreachable];
77+
_8 = copy (_5.1: std::ptr::Alignment);
78+
_9 = alloc::alloc::__rust_dealloc(move _7, move _6, move _8) -> [return: bb3, unwind unreachable];
9779
}
9880

9981
bb3: {
10082
StorageDead(_8);
83+
StorageDead(_7);
10184
goto -> bb4;
10285
}
10386

10487
bb4: {
10588
StorageDead(_2);
89+
StorageDead(_5);
10690
return;
10791
}
10892
}

0 commit comments

Comments
 (0)