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),
}),
}
}
51 changes: 36 additions & 15 deletions compiler/rustc_mir_transform/src/instsimplify.rs
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ impl<'tcx> crate::MirPass<'tcx> for InstSimplify {

let terminator = block.terminator.as_mut().unwrap();
ctx.simplify_primitive_clone(terminator, &mut block.statements);
ctx.simplify_align_of_slice_val(terminator, &mut block.statements);
ctx.simplify_size_or_align_of_val(terminator, &mut block.statements);
ctx.simplify_intrinsic_assert(terminator);
ctx.simplify_nounwind_call(terminator);
simplify_duplicate_switch_targets(terminator);
Expand Down Expand Up @@ -246,13 +246,18 @@ impl<'tcx> InstSimplifyContext<'_, 'tcx> {
terminator.kind = TerminatorKind::Goto { target: *destination_block };
}

// Convert `align_of_val::<[T]>(ptr)` to `align_of::<T>()`, since the
// alignment of a slice doesn't actually depend on metadata at all
// and the element type is always `Sized`.
//
// This is here so it can run after inlining, where it's more useful.
// (LowerIntrinsics is done in cleanup, before the optimization passes.)
fn simplify_align_of_slice_val(
/// Simplify `size_of_val` and `align_of_val` if we don't actually need
/// to look at the value in order to calculate the result:
/// - For `Sized` types we can always do this for both,
/// - For `align_of_val::<[T]>` we can return `align_of::<T>()`, since it
/// doesn't depend on the slice's length and the elements are sized.
///
/// This is here so it can run after inlining, where it's more useful.
/// (LowerIntrinsics is done in cleanup, before the optimization passes.)
///
/// Note that we intentionally just produce the lang item constants so this
/// works on generic types and avoids any risk of layout calculation cycles.
fn simplify_size_or_align_of_val(
&self,
terminator: &mut Terminator<'tcx>,
statements: &mut Vec<Statement<'tcx>>,
Expand All @@ -263,19 +268,35 @@ impl<'tcx> InstSimplifyContext<'_, 'tcx> {
} = &terminator.kind
&& args.len() == 1
&& let Some((fn_def_id, generics)) = func.const_fn_def()
&& self.tcx.is_intrinsic(fn_def_id, sym::align_of_val)
&& let ty::Slice(elem_ty) = *generics.type_at(0).kind()
{
let align_def_id = self.tcx.require_lang_item(LangItem::AlignOf, source_info.span);
let align_const = Operand::unevaluated_constant(
let lang_item = if self.tcx.is_intrinsic(fn_def_id, sym::size_of_val) {
LangItem::SizeOf
} else if self.tcx.is_intrinsic(fn_def_id, sym::align_of_val) {
LangItem::AlignOf
} else {
return;
};
let generic_ty = generics.type_at(0);
let ty = if generic_ty.is_sized(self.tcx, self.typing_env) {
generic_ty
} else if let LangItem::AlignOf = lang_item
&& let ty::Slice(elem_ty) = *generic_ty.kind()
{
elem_ty
} else {
return;
};

let const_def_id = self.tcx.require_lang_item(lang_item, source_info.span);
let const_op = Operand::unevaluated_constant(
self.tcx,
align_def_id,
&[elem_ty.into()],
const_def_id,
&[ty.into()],
source_info.span,
);
statements.push(Statement::new(
source_info,
StatementKind::Assign(Box::new((*destination, Rvalue::Use(align_const)))),
StatementKind::Assign(Box::new((*destination, Rvalue::Use(const_op)))),
));
terminator.kind = TerminatorKind::Goto { target: *destination_block };
}
Expand Down
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
Loading
Loading