Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 10 additions & 4 deletions compiler/rustc_codegen_cranelift/example/mini_core.rs
Original file line number Diff line number Diff line change
Expand Up @@ -645,6 +645,12 @@ pub union MaybeUninit<T> {
pub value: ManuallyDrop<T>,
}

pub mod ptr {
#[lang = "Alignment"]
#[repr(transparent)]
pub struct Alignment(pub usize);
}

pub mod intrinsics {
#[rustc_intrinsic]
pub fn abort() -> !;
Expand All @@ -653,9 +659,9 @@ pub mod intrinsics {
#[rustc_intrinsic]
pub unsafe fn size_of_val<T: ?crate::Sized>(val: *const T) -> usize;
#[rustc_intrinsic]
pub const fn align_of<T>() -> usize;
pub const fn align_of<T>() -> crate::ptr::Alignment;
#[rustc_intrinsic]
pub unsafe fn align_of_val<T: ?crate::Sized>(val: *const T) -> usize;
pub unsafe fn align_of_val<T: ?crate::Sized>(val: *const T) -> crate::ptr::Alignment;
#[rustc_intrinsic]
pub unsafe fn copy<T>(src: *const T, dst: *mut T, count: usize);
#[rustc_intrinsic]
Expand Down Expand Up @@ -723,15 +729,15 @@ pub const fn size_of<T>() -> usize {
}

pub const fn align_of<T>() -> usize {
<T as SizedTypeProperties>::ALIGN
<T as SizedTypeProperties>::ALIGN.0
}

trait SizedTypeProperties: Sized {
#[lang = "mem_size_const"]
const SIZE: usize = intrinsics::size_of::<Self>();

#[lang = "mem_align_const"]
const ALIGN: usize = intrinsics::align_of::<Self>();
const ALIGN: crate::ptr::Alignment = intrinsics::align_of::<Self>();
}
impl<T> SizedTypeProperties for T {}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -216,7 +216,7 @@ fn main() {
assert_eq!(intrinsics::size_of_val(&0u32) as u8, 4);

assert_eq!(align_of::<u16>() as u8, 2);
assert_eq!(intrinsics::align_of_val(&a) as u8, align_of::<&str>() as u8);
assert_eq!(intrinsics::align_of_val(&a).0 as u8, align_of::<&str>() as u8);

let u8_needs_drop = const { intrinsics::needs_drop::<u8>() };
assert!(!u8_needs_drop);
Expand Down
3 changes: 2 additions & 1 deletion compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -602,7 +602,8 @@ fn codegen_regular_intrinsic_call<'tcx>(
None
};
let (_size, align) = crate::unsize::size_and_align_of(fx, layout, meta);
ret.write_cvalue(fx, CValue::by_val(align, usize_layout));
let alignment_layout = fx.layout_of(fx.tcx.ty_alignment(source_info.span));
ret.write_cvalue(fx, CValue::by_val(align, alignment_layout));
}

sym::vtable_size => {
Expand Down
14 changes: 10 additions & 4 deletions compiler/rustc_codegen_gcc/example/mini_core.rs
Original file line number Diff line number Diff line change
Expand Up @@ -651,6 +651,12 @@ pub union MaybeUninit<T> {
pub value: ManuallyDrop<T>,
}

pub mod ptr {
#[lang = "Alignment"]
#[repr(transparent)]
pub struct Alignment(pub usize);
}

pub mod intrinsics {
#[rustc_intrinsic]
pub const fn black_box<T>(_dummy: T) -> T;
Expand All @@ -661,9 +667,9 @@ pub mod intrinsics {
#[rustc_intrinsic]
pub unsafe fn size_of_val<T: ?::Sized>(val: *const T) -> usize;
#[rustc_intrinsic]
pub const fn align_of<T>() -> usize;
pub const fn align_of<T>() -> crate::ptr::Alignment;
#[rustc_intrinsic]
pub unsafe fn align_of_val<T: ?::Sized>(val: *const T) -> usize;
pub unsafe fn align_of_val<T: ?::Sized>(val: *const T) -> crate::ptr::Alignment;
#[rustc_intrinsic]
pub unsafe fn copy<T>(src: *const T, dst: *mut T, count: usize);
#[rustc_intrinsic]
Expand Down Expand Up @@ -704,15 +710,15 @@ pub const fn size_of<T>() -> usize {
}

pub const fn align_of<T>() -> usize {
<T as SizedTypeProperties>::ALIGN
<T as SizedTypeProperties>::ALIGN.0
}

trait SizedTypeProperties: Sized {
#[lang = "mem_size_const"]
const SIZE: usize = intrinsics::size_of::<Self>();

#[lang = "mem_align_const"]
const ALIGN: usize = intrinsics::align_of::<Self>();
const ALIGN: crate::ptr::Alignment = intrinsics::align_of::<Self>();
}

impl<T> SizedTypeProperties for T {}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -196,7 +196,7 @@ fn main() {
assert_eq!(intrinsics::size_of_val(&0u32) as u8, 4);

assert_eq!(align_of::<u16>() as u8, 2);
assert_eq!(intrinsics::align_of_val(&a) as u8, align_of::<&str>() as u8);
assert_eq!(intrinsics::align_of_val(&a).0 as u8, align_of::<&str>() as u8);

let u8_needs_drop = const { intrinsics::needs_drop::<u8>() };
assert!(!u8_needs_drop);
Expand Down
1 change: 1 addition & 0 deletions compiler/rustc_hir/src/lang_items.rs
Original file line number Diff line number Diff line change
Expand Up @@ -156,6 +156,7 @@ language_item_table! {
MetaSized, sym::meta_sized, meta_sized_trait, Target::Trait, GenericRequirement::Exact(0);
PointeeSized, sym::pointee_sized, pointee_sized_trait, Target::Trait, GenericRequirement::Exact(0);
Unsize, sym::unsize, unsize_trait, Target::Trait, GenericRequirement::Minimum(1);
Alignment, sym::Alignment, alignment_type, Target::Struct, GenericRequirement::Exact(0);
AlignOf, sym::mem_align_const, align_const, Target::AssocConst, GenericRequirement::Exact(0);
SizeOf, sym::mem_size_const, size_const, Target::AssocConst, GenericRequirement::Exact(0);
OffsetOf, sym::offset_of, offset_of, Target::Fn, GenericRequirement::Exact(1);
Expand Down
8 changes: 4 additions & 4 deletions compiler/rustc_hir_analysis/src/check/intrinsic.rs
Original file line number Diff line number Diff line change
Expand Up @@ -292,10 +292,10 @@ pub(crate) fn check_intrinsic_type(
sym::amdgpu_dispatch_ptr => (0, 0, vec![], Ty::new_imm_ptr(tcx, tcx.types.unit)),
sym::unreachable => (0, 0, vec![], tcx.types.never),
sym::breakpoint => (0, 0, vec![], tcx.types.unit),
sym::size_of | sym::align_of | sym::variant_count => (1, 0, vec![], tcx.types.usize),
sym::size_of_val | sym::align_of_val => {
(1, 0, vec![Ty::new_imm_ptr(tcx, param(0))], tcx.types.usize)
}
sym::size_of | sym::variant_count => (1, 0, vec![], tcx.types.usize),
sym::align_of => (1, 0, vec![], tcx.ty_alignment(span)),
sym::size_of_val => (1, 0, vec![Ty::new_imm_ptr(tcx, param(0))], tcx.types.usize),
sym::align_of_val => (1, 0, vec![Ty::new_imm_ptr(tcx, param(0))], tcx.ty_alignment(span)),
sym::offset_of => (1, 0, vec![tcx.types.u32, tcx.types.u32], tcx.types.usize),
sym::rustc_peek => (1, 0, vec![param(0)], param(0)),
sym::caller_location => (0, 0, vec![], tcx.caller_location_ty()),
Expand Down
7 changes: 7 additions & 0 deletions compiler/rustc_middle/src/ty/context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1079,6 +1079,13 @@ impl<'tcx> TyCtxt<'tcx> {
self.type_of(ordering_enum).no_bound_vars().unwrap()
}

/// Gets a `Ty` representing the [`LangItem::Alignment`]
#[track_caller]
pub fn ty_alignment(self, span: Span) -> Ty<'tcx> {
let alignment = self.require_lang_item(hir::LangItem::Alignment, span);
self.type_of(alignment).no_bound_vars().unwrap()
}

/// Obtain the given diagnostic item's `DefId`. Use `is_diagnostic_item` if you just want to
/// compare against another `DefId`, since `is_diagnostic_item` is cheaper.
pub fn get_diagnostic_item(self, name: Symbol) -> Option<DefId> {
Expand Down
17 changes: 13 additions & 4 deletions compiler/rustc_mir_transform/src/check_alignment.rs
Original file line number Diff line number Diff line change
Expand Up @@ -55,14 +55,23 @@ fn insert_alignment_check<'tcx>(
stmts.push(Statement::new(source_info, StatementKind::Assign(Box::new((thin_ptr, rvalue)))));

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

// Get the alignment of the pointee
let align_def_id = tcx.require_lang_item(LangItem::AlignOf, source_info.span);
let alignment_usize =
local_decls.push(LocalDecl::with_source_info(tcx.types.usize, source_info)).into();
let alignment =
Operand::unevaluated_constant(tcx, align_def_id, &[pointee_ty.into()], source_info.span);
stmts.push(Statement::new(
source_info,
StatementKind::Assign(Box::new((
alignment_usize,
Rvalue::Cast(CastKind::Transmute, alignment.clone(), tcx.types.usize),
))),
));

// Subtract 1 from the alignment to get the alignment mask
let alignment_mask =
Expand All @@ -76,7 +85,7 @@ fn insert_alignment_check<'tcx>(
source_info,
StatementKind::Assign(Box::new((
alignment_mask,
Rvalue::BinaryOp(BinOp::Sub, Box::new((alignment.clone(), one))),
Rvalue::BinaryOp(BinOp::SubUnchecked, Box::new((Operand::Move(alignment_usize), one))),
))),
));

Expand Down Expand Up @@ -139,10 +148,10 @@ fn insert_alignment_check<'tcx>(
// Emit a check that asserts on the alignment and otherwise triggers a
// AssertKind::MisalignedPointerDereference.
PointerCheck {
cond: Operand::Copy(is_ok),
cond: Operand::Move(is_ok),
assert_kind: Box::new(AssertKind::MisalignedPointerDereference {
required: alignment,
found: Operand::Copy(addr),
found: Operand::Move(addr),
}),
}
}
4 changes: 2 additions & 2 deletions library/alloc/src/alloc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -484,8 +484,8 @@ unsafe impl const Allocator for Global {
#[lang = "exchange_malloc"]
#[inline]
#[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
unsafe fn exchange_malloc(size: usize, align: usize) -> *mut u8 {
let layout = unsafe { Layout::from_size_align_unchecked(size, align) };
unsafe fn exchange_malloc(size: usize, align: Alignment) -> *mut u8 {
let layout = unsafe { Layout::from_size_alignment_unchecked(size, align) };
match Global.allocate(layout) {
Ok(ptr) => ptr.as_mut_ptr(),
Err(_) => handle_alloc_error(layout),
Expand Down
4 changes: 2 additions & 2 deletions library/core/src/intrinsics/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2802,7 +2802,7 @@ pub const fn size_of<T>() -> usize;
#[unstable(feature = "core_intrinsics", issue = "none")]
#[rustc_intrinsic_const_stable_indirect]
#[rustc_intrinsic]
pub const fn align_of<T>() -> usize;
pub const fn align_of<T>() -> ptr::Alignment;

/// The offset of a field inside a type.
///
Expand Down Expand Up @@ -2862,7 +2862,7 @@ pub const unsafe fn size_of_val<T: ?Sized>(ptr: *const T) -> usize;
#[unstable(feature = "core_intrinsics", issue = "none")]
#[rustc_intrinsic]
#[rustc_intrinsic_const_stable_indirect]
pub const unsafe fn align_of_val<T: ?Sized>(ptr: *const T) -> usize;
pub const unsafe fn align_of_val<T: ?Sized>(ptr: *const T) -> ptr::Alignment;

/// Compute the type information of a concrete type.
/// It can only be called at compile time, the backends do
Expand Down
24 changes: 8 additions & 16 deletions library/core/src/mem/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -450,7 +450,7 @@ pub const unsafe fn size_of_val_raw<T: ?Sized>(val: *const T) -> usize {
#[stable(feature = "rust1", since = "1.0.0")]
#[deprecated(note = "use `align_of` instead", since = "1.2.0", suggestion = "align_of")]
pub fn min_align_of<T>() -> usize {
<T as SizedTypeProperties>::ALIGN
align_of::<T>()
}

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

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

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

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

/// Returns `true` if dropping values of type `T` matters.
Expand Down Expand Up @@ -1256,14 +1254,8 @@ pub trait SizedTypeProperties: Sized {
#[doc(hidden)]
#[unstable(feature = "sized_type_properties", issue = "none")]
#[lang = "mem_align_const"]
const ALIGN: usize = intrinsics::align_of::<Self>();

#[doc(hidden)]
#[unstable(feature = "ptr_alignment_type", issue = "102070")]
const ALIGNMENT: Alignment = {
// This can't panic since type alignment is always a power of two.
Alignment::new(Self::ALIGN).unwrap()
};
// #[unstable(feature = "ptr_alignment_type", issue = "102070")]
const ALIGNMENT: Alignment = intrinsics::align_of::<Self>();

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

/// The largest safe length for a `[Self]`.
Expand Down
14 changes: 7 additions & 7 deletions library/core/src/ptr/alignment.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,18 @@
use crate::marker::MetaSized;
use crate::num::NonZero;
use crate::ub_checks::assert_unsafe_precondition;
use crate::{cmp, fmt, hash, mem, num};
use crate::{cmp, fmt, hash, intrinsics, mem, num};

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

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

/// Creates an `Alignment` from a `usize`, or returns `None` if it's
Expand Down
9 changes: 8 additions & 1 deletion tests/auxiliary/minicore.rs
Original file line number Diff line number Diff line change
Expand Up @@ -271,6 +271,12 @@ trait Drop {
fn drop(&mut self);
}

pub mod ptr {
#[lang = "Alignment"]
#[repr(transparent)]
pub struct Alignment(usize);
}

pub mod mem {
#[rustc_nounwind]
#[rustc_intrinsic]
Expand All @@ -279,9 +285,10 @@ pub mod mem {
#[rustc_nounwind]
#[rustc_intrinsic]
pub const fn size_of<T>() -> usize;

#[rustc_nounwind]
#[rustc_intrinsic]
pub const fn align_of<T>() -> usize;
pub const fn align_of<T>() -> crate::ptr::Alignment;
}

#[lang = "c_void"]
Expand Down
3 changes: 1 addition & 2 deletions tests/codegen-units/item-collection/opaque-return-impls.rs
Original file line number Diff line number Diff line change
Expand Up @@ -46,8 +46,7 @@ pub fn foo2() -> Box<dyn TestTrait2> {
//~ MONO_ITEM fn foo2
//~ MONO_ITEM fn std::alloc::Global::alloc_impl_runtime
//~ MONO_ITEM fn std::boxed::Box::<TestStruct2>::new
//~ MONO_ITEM fn std::alloc::Layout::from_size_align_unchecked::precondition_check
//~ MONO_ITEM fn std::ptr::Alignment::new_unchecked::precondition_check
//~ MONO_ITEM fn std::alloc::Layout::from_size_alignment_unchecked::precondition_check
//~ MONO_ITEM fn std::ptr::NonNull::<T>::new_unchecked::precondition_check

struct Counter {
Expand Down
19 changes: 19 additions & 0 deletions tests/mir-opt/alignment_checks.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
//@ compile-flags: -Copt-level=1 -Zmir-opt-level=2 -Zub-checks
//@ only-64bit
// EMIT_MIR_FOR_EACH_PANIC_STRATEGY

#![crate_type = "lib"]

// The diff shows exactly what is generated by the pass;
// then we check the final `-O1` output for people who want to run them
// without the codegen being too terrible.

// EMIT_MIR alignment_checks.sized_ptr.CheckAlignment.diff
pub unsafe fn sized_ptr(ptr: *const u32) -> u32 {
// CHECK-LABEL: fn sized_ptr(_1: *const u32)
// CHECK: _2 = copy _1 as usize (Transmute);
// CHECK: _3 = BitAnd(copy _2, const 3_usize);
// CHECK: _4 = Eq(copy _3, const 0_usize);
// CHECK: assert(move _4,
*ptr
}
Loading
Loading