Skip to content

Commit 864bde0

Browse files
committed
Make the alignment intrinsics return ptr::Alignment
1 parent 4e79e36 commit 864bde0

28 files changed

Lines changed: 224 additions & 270 deletions

compiler/rustc_hir/src/lang_items.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -168,6 +168,7 @@ language_item_table! {
168168
MetaSized, sym::meta_sized, meta_sized_trait, Target::Trait, GenericRequirement::Exact(0);
169169
PointeeSized, sym::pointee_sized, pointee_sized_trait, Target::Trait, GenericRequirement::Exact(0);
170170
Unsize, sym::unsize, unsize_trait, Target::Trait, GenericRequirement::Minimum(1);
171+
Alignment, sym::Alignment, alignment_type, Target::Struct, GenericRequirement::Exact(0);
171172
AlignOf, sym::mem_align_const, align_const, Target::AssocConst, GenericRequirement::Exact(0);
172173
SizeOf, sym::mem_size_const, size_const, Target::AssocConst, GenericRequirement::Exact(0);
173174
OffsetOf, sym::offset_of, offset_of, Target::Fn, GenericRequirement::Exact(1);

compiler/rustc_hir_analysis/src/check/intrinsic.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -291,10 +291,10 @@ pub(crate) fn check_intrinsic_type(
291291
sym::amdgpu_dispatch_ptr => (0, 0, vec![], Ty::new_imm_ptr(tcx, tcx.types.unit)),
292292
sym::unreachable => (0, 0, vec![], tcx.types.never),
293293
sym::breakpoint => (0, 0, vec![], tcx.types.unit),
294-
sym::size_of | sym::align_of | sym::variant_count => (1, 0, vec![], tcx.types.usize),
295-
sym::size_of_val | sym::align_of_val => {
296-
(1, 0, vec![Ty::new_imm_ptr(tcx, param(0))], tcx.types.usize)
297-
}
294+
sym::size_of | sym::variant_count => (1, 0, vec![], tcx.types.usize),
295+
sym::align_of => (1, 0, vec![], tcx.ty_alignment(span)),
296+
sym::size_of_val => (1, 0, vec![Ty::new_imm_ptr(tcx, param(0))], tcx.types.usize),
297+
sym::align_of_val => (1, 0, vec![Ty::new_imm_ptr(tcx, param(0))], tcx.ty_alignment(span)),
298298
sym::offset_of => (1, 0, vec![tcx.types.u32, tcx.types.u32], tcx.types.usize),
299299
sym::rustc_peek => (1, 0, vec![param(0)], param(0)),
300300
sym::caller_location => (0, 0, vec![], tcx.caller_location_ty()),

compiler/rustc_middle/src/ty/context.rs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1079,6 +1079,13 @@ 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+
#[track_caller]
1084+
pub fn ty_alignment(self, span: Span) -> Ty<'tcx> {
1085+
let alignment = self.require_lang_item(hir::LangItem::Alignment, span);
1086+
self.type_of(alignment).no_bound_vars().unwrap()
1087+
}
1088+
10821089
/// Obtain the given diagnostic item's `DefId`. Use `is_diagnostic_item` if you just want to
10831090
/// compare against another `DefId`, since `is_diagnostic_item` is cheaper.
10841091
pub fn get_diagnostic_item(self, name: Symbol) -> Option<DefId> {

compiler/rustc_mir_transform/src/check_alignment.rs

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -55,14 +55,23 @@ fn insert_alignment_check<'tcx>(
5555
stmts.push(Statement::new(source_info, StatementKind::Assign(Box::new((thin_ptr, rvalue)))));
5656

5757
// Transmute the pointer to a usize (equivalent to `ptr.addr()`).
58-
let rvalue = Rvalue::Cast(CastKind::Transmute, Operand::Copy(thin_ptr), tcx.types.usize);
58+
let rvalue = Rvalue::Cast(CastKind::Transmute, Operand::Move(thin_ptr), tcx.types.usize);
5959
let addr = local_decls.push(LocalDecl::with_source_info(tcx.types.usize, source_info)).into();
6060
stmts.push(Statement::new(source_info, StatementKind::Assign(Box::new((addr, rvalue)))));
6161

6262
// Get the alignment of the pointee
6363
let align_def_id = tcx.require_lang_item(LangItem::AlignOf, source_info.span);
64+
let alignment_usize =
65+
local_decls.push(LocalDecl::with_source_info(tcx.types.usize, source_info)).into();
6466
let alignment =
6567
Operand::unevaluated_constant(tcx, align_def_id, &[pointee_ty.into()], source_info.span);
68+
stmts.push(Statement::new(
69+
source_info,
70+
StatementKind::Assign(Box::new((
71+
alignment_usize,
72+
Rvalue::Cast(CastKind::Transmute, alignment.clone(), tcx.types.usize),
73+
))),
74+
));
6675

6776
// Subtract 1 from the alignment to get the alignment mask
6877
let alignment_mask =
@@ -76,7 +85,7 @@ fn insert_alignment_check<'tcx>(
7685
source_info,
7786
StatementKind::Assign(Box::new((
7887
alignment_mask,
79-
Rvalue::BinaryOp(BinOp::Sub, Box::new((alignment.clone(), one))),
88+
Rvalue::BinaryOp(BinOp::SubUnchecked, Box::new((Operand::Move(alignment_usize), one))),
8089
))),
8190
));
8291

@@ -139,10 +148,10 @@ fn insert_alignment_check<'tcx>(
139148
// Emit a check that asserts on the alignment and otherwise triggers a
140149
// AssertKind::MisalignedPointerDereference.
141150
PointerCheck {
142-
cond: Operand::Copy(is_ok),
151+
cond: Operand::Move(is_ok),
143152
assert_kind: Box::new(AssertKind::MisalignedPointerDereference {
144153
required: alignment,
145-
found: Operand::Copy(addr),
154+
found: Operand::Move(addr),
146155
}),
147156
}
148157
}

library/alloc/src/alloc.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -484,8 +484,8 @@ unsafe impl const Allocator for Global {
484484
#[lang = "exchange_malloc"]
485485
#[inline]
486486
#[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
487-
unsafe fn exchange_malloc(size: usize, align: usize) -> *mut u8 {
488-
let layout = unsafe { Layout::from_size_align_unchecked(size, align) };
487+
unsafe fn exchange_malloc(size: usize, align: Alignment) -> *mut u8 {
488+
let layout = unsafe { Layout::from_size_alignment_unchecked(size, align) };
489489
match Global.allocate(layout) {
490490
Ok(ptr) => ptr.as_mut_ptr(),
491491
Err(_) => handle_alloc_error(layout),

library/core/src/intrinsics/mod.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2789,7 +2789,7 @@ pub const fn size_of<T>() -> usize;
27892789
#[unstable(feature = "core_intrinsics", issue = "none")]
27902790
#[rustc_intrinsic_const_stable_indirect]
27912791
#[rustc_intrinsic]
2792-
pub const fn align_of<T>() -> usize;
2792+
pub const fn align_of<T>() -> ptr::Alignment;
27932793

27942794
/// The offset of a field inside a type.
27952795
///
@@ -2849,7 +2849,7 @@ pub const unsafe fn size_of_val<T: ?Sized>(ptr: *const T) -> usize;
28492849
#[unstable(feature = "core_intrinsics", issue = "none")]
28502850
#[rustc_intrinsic]
28512851
#[rustc_intrinsic_const_stable_indirect]
2852-
pub const unsafe fn align_of_val<T: ?Sized>(ptr: *const T) -> usize;
2852+
pub const unsafe fn align_of_val<T: ?Sized>(ptr: *const T) -> ptr::Alignment;
28532853

28542854
/// Compute the type information of a concrete type.
28552855
/// It can only be called at compile time, the backends do

library/core/src/mem/mod.rs

Lines changed: 8 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -450,7 +450,7 @@ pub const unsafe fn size_of_val_raw<T: ?Sized>(val: *const T) -> usize {
450450
#[stable(feature = "rust1", since = "1.0.0")]
451451
#[deprecated(note = "use `align_of` instead", since = "1.2.0", suggestion = "align_of")]
452452
pub fn min_align_of<T>() -> usize {
453-
<T as SizedTypeProperties>::ALIGN
453+
align_of::<T>()
454454
}
455455

456456
/// Returns the [ABI]-required minimum alignment of the type of the value that `val` points to in
@@ -473,8 +473,7 @@ pub fn min_align_of<T>() -> usize {
473473
#[stable(feature = "rust1", since = "1.0.0")]
474474
#[deprecated(note = "use `align_of_val` instead", since = "1.2.0", suggestion = "align_of_val")]
475475
pub fn min_align_of_val<T: ?Sized>(val: &T) -> usize {
476-
// SAFETY: val is a reference, so it's a valid raw pointer
477-
unsafe { intrinsics::align_of_val(val) }
476+
align_of_val(val)
478477
}
479478

480479
/// Returns the [ABI]-required minimum alignment of a type in bytes.
@@ -497,7 +496,7 @@ pub fn min_align_of_val<T: ?Sized>(val: &T) -> usize {
497496
#[rustc_const_stable(feature = "const_align_of", since = "1.24.0")]
498497
#[rustc_diagnostic_item = "mem_align_of"]
499498
pub const fn align_of<T>() -> usize {
500-
<T as SizedTypeProperties>::ALIGN
499+
Alignment::of::<T>().as_usize()
501500
}
502501

503502
/// Returns the [ABI]-required minimum alignment of the type of the value that `val` points to in
@@ -517,8 +516,7 @@ pub const fn align_of<T>() -> usize {
517516
#[stable(feature = "rust1", since = "1.0.0")]
518517
#[rustc_const_stable(feature = "const_align_of_val", since = "1.85.0")]
519518
pub const fn align_of_val<T: ?Sized>(val: &T) -> usize {
520-
// SAFETY: val is a reference, so it's a valid raw pointer
521-
unsafe { intrinsics::align_of_val(val) }
519+
Alignment::of_val(val).as_usize()
522520
}
523521

524522
/// Returns the [ABI]-required minimum alignment of the type of the value that `val` points to in
@@ -565,7 +563,7 @@ pub const fn align_of_val<T: ?Sized>(val: &T) -> usize {
565563
#[unstable(feature = "layout_for_ptr", issue = "69835")]
566564
pub const unsafe fn align_of_val_raw<T: ?Sized>(val: *const T) -> usize {
567565
// SAFETY: the caller must provide a valid raw pointer
568-
unsafe { intrinsics::align_of_val(val) }
566+
unsafe { Alignment::of_val_raw(val) }.as_usize()
569567
}
570568

571569
/// Returns `true` if dropping values of type `T` matters.
@@ -1256,14 +1254,8 @@ pub trait SizedTypeProperties: Sized {
12561254
#[doc(hidden)]
12571255
#[unstable(feature = "sized_type_properties", issue = "none")]
12581256
#[lang = "mem_align_const"]
1259-
const ALIGN: usize = intrinsics::align_of::<Self>();
1260-
1261-
#[doc(hidden)]
1262-
#[unstable(feature = "ptr_alignment_type", issue = "102070")]
1263-
const ALIGNMENT: Alignment = {
1264-
// This can't panic since type alignment is always a power of two.
1265-
Alignment::new(Self::ALIGN).unwrap()
1266-
};
1257+
// #[unstable(feature = "ptr_alignment_type", issue = "102070")]
1258+
const ALIGNMENT: Alignment = intrinsics::align_of::<Self>();
12671259

12681260
/// `true` if this type requires no storage.
12691261
/// `false` if its [size](size_of) is greater than zero.
@@ -1300,7 +1292,7 @@ pub trait SizedTypeProperties: Sized {
13001292
// SAFETY: if the type is instantiated, rustc already ensures that its
13011293
// layout is valid. Use the unchecked constructor to avoid inserting a
13021294
// panicking codepath that needs to be optimized out.
1303-
unsafe { Layout::from_size_align_unchecked(Self::SIZE, Self::ALIGN) }
1295+
unsafe { Layout::from_size_alignment_unchecked(Self::SIZE, Self::ALIGNMENT) }
13041296
};
13051297

13061298
/// The largest safe length for a `[Self]`.

library/core/src/ptr/alignment.rs

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -3,15 +3,18 @@
33
use crate::marker::MetaSized;
44
use crate::num::NonZero;
55
use crate::ub_checks::assert_unsafe_precondition;
6-
use crate::{cmp, fmt, hash, mem, num};
6+
use crate::{cmp, fmt, hash, intrinsics, mem, num};
77

88
/// A type storing a `usize` which is a power of two, and thus
99
/// represents a possible alignment in the Rust abstract machine.
1010
///
1111
/// Note that particularly large alignments, while representable in this type,
1212
/// are likely not to be supported by actual allocators and linkers.
1313
#[unstable(feature = "ptr_alignment_type", issue = "102070")]
14+
// No special behaviour, but used as the return type from an intrinsic
15+
#[lang = "Alignment"]
1416
#[derive(Copy, Clone, PartialEq, Eq)]
17+
// This being transparent is critical for its use in `__rust_alloc` and friends
1518
#[repr(transparent)]
1619
pub struct Alignment {
1720
// This field is never used directly (nor is the enum),
@@ -73,9 +76,8 @@ impl Alignment {
7376
#[must_use]
7477
#[unstable(feature = "ptr_alignment_type", issue = "102070")]
7578
pub const fn of_val<T: MetaSized>(val: &T) -> Self {
76-
let align = mem::align_of_val(val);
77-
// SAFETY: `align_of_val` returns valid alignment
78-
unsafe { Alignment::new_unchecked(align) }
79+
// SAFETY: val is a reference, so it's a valid raw pointer
80+
unsafe { Alignment::of_val_raw(val) }
7981
}
8082

8183
/// Returns the [ABI]-required minimum alignment of the type of the value that `val` points to.
@@ -122,9 +124,7 @@ impl Alignment {
122124
// #[unstable(feature = "layout_for_ptr", issue = "69835")]
123125
pub const unsafe fn of_val_raw<T: MetaSized>(val: *const T) -> Self {
124126
// SAFETY: precondition propagated to the caller
125-
let align = unsafe { mem::align_of_val_raw(val) };
126-
// SAFETY: `align_of_val_raw` returns valid alignment
127-
unsafe { Alignment::new_unchecked(align) }
127+
unsafe { intrinsics::align_of_val(val) }
128128
}
129129

130130
/// Creates an `Alignment` from a `usize`, or returns `None` if it's

tests/auxiliary/minicore.rs

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -268,6 +268,12 @@ trait Drop {
268268
fn drop(&mut self);
269269
}
270270

271+
pub mod ptr {
272+
#[lang = "Alignment"]
273+
#[repr(transparent)]
274+
pub struct Alignment(usize);
275+
}
276+
271277
pub mod mem {
272278
#[rustc_nounwind]
273279
#[rustc_intrinsic]
@@ -276,9 +282,10 @@ pub mod mem {
276282
#[rustc_nounwind]
277283
#[rustc_intrinsic]
278284
pub const fn size_of<T>() -> usize;
285+
279286
#[rustc_nounwind]
280287
#[rustc_intrinsic]
281-
pub const fn align_of<T>() -> usize;
288+
pub const fn align_of<T>() -> crate::ptr::Alignment;
282289
}
283290

284291
#[lang = "c_void"]

tests/mir-opt/alignment_checks.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,6 @@ pub unsafe fn sized_ptr(ptr: *const u32) -> u32 {
1414
// CHECK: _2 = copy _1 as usize (Transmute);
1515
// CHECK: _3 = BitAnd(copy _2, const 3_usize);
1616
// CHECK: _4 = Eq(copy _3, const 0_usize);
17-
// CHECK: assert(copy _4,
17+
// CHECK: assert(move _4,
1818
*ptr
1919
}

0 commit comments

Comments
 (0)