Skip to content
Draft
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 @@ -686,6 +686,12 @@ pub union MaybeUninit<T> {
pub value: ManuallyDrop<T>,
}

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

pub mod intrinsics {
#[rustc_intrinsic]
pub fn abort() -> !;
Expand All @@ -694,9 +700,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::mem::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::mem::Alignment;
#[rustc_intrinsic]
pub unsafe fn copy<T>(src: *const T, dst: *mut T, count: usize);
#[rustc_intrinsic]
Expand Down Expand Up @@ -764,15 +770,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::mem::Alignment = intrinsics::align_of::<Self>();
}
impl<T> SizedTypeProperties for T {}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -220,7 +220,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 @@ -592,7 +592,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 @@ -694,6 +694,12 @@ pub union MaybeUninit<T> {
pub value: ManuallyDrop<T>,
}

pub mod mem {
#[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 @@ -704,9 +710,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::mem::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::mem::Alignment;
#[rustc_intrinsic]
pub unsafe fn copy<T>(src: *const T, dst: *mut T, count: usize);
#[rustc_intrinsic]
Expand Down Expand Up @@ -747,15 +753,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::mem::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::size_of_type_id => (0, 0, vec![type_id_ty()], Ty::new_option(tcx, tcx.types.usize)),
sym::offset_of => (1, 0, vec![tcx.types.u32, tcx.types.u32], tcx.types.usize),
sym::field_offset => (1, 0, vec![], tcx.types.usize),
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 @@ -979,6 +979,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 @@ -138,10 +147,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: 28 additions & 23 deletions library/alloc/src/alloc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -216,18 +216,16 @@ impl Global {

#[inline]
#[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
fn deallocate_impl_runtime(ptr: NonNull<u8>, layout: Layout) {
if layout.size() != 0 {
// SAFETY:
// * We have checked that `layout` is non-zero in size.
// * The caller is obligated to provide a layout that "fits", and in this case,
// "fit" always means a layout that is equal to the original, because our
// `allocate()`, `grow()`, and `shrink()` implementations never returns a larger
// allocation than requested.
// * Other conditions must be upheld by the caller, as per `Allocator::deallocate()`'s
// safety documentation.
unsafe { dealloc_nonnull(ptr, layout) }
}
fn deallocate_nonzero_impl_runtime(ptr: NonNull<u8>, layout: Layout) {
// SAFETY:
// * The caller provided a `layout` that is non-zero in size.
// * The caller is obligated to provide a layout that "fits", and in this case,
// "fit" always means a layout that is equal to the original, because our
// `allocate()`, `grow()`, and `shrink()` implementations never returns a larger
// allocation than requested.
// * Other conditions must be upheld by the caller, as per `Allocator::deallocate()`'s
// safety documentation.
unsafe { dealloc_nonnull(ptr, layout) }
}

// SAFETY: Same as `Allocator::grow`
Expand Down Expand Up @@ -340,11 +338,11 @@ impl Global {
#[inline]
#[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
#[rustc_const_unstable(feature = "const_heap", issue = "79597")]
const unsafe fn deallocate_impl(&self, ptr: NonNull<u8>, layout: Layout) {
const unsafe fn deallocate_nonzero_impl(&self, ptr: NonNull<u8>, layout: Layout) {
core::intrinsics::const_eval_select(
(ptr, layout),
Global::deallocate_impl_const,
Global::deallocate_impl_runtime,
Global::deallocate_nonzero_impl_const,
Global::deallocate_nonzero_impl_runtime,
)
}

Expand Down Expand Up @@ -405,12 +403,10 @@ impl Global {
#[inline]
#[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
#[rustc_const_unstable(feature = "const_heap", issue = "79597")]
const fn deallocate_impl_const(ptr: NonNull<u8>, layout: Layout) {
if layout.size() != 0 {
// SAFETY: We checked for nonzero size; other preconditions must be upheld by caller.
unsafe {
core::intrinsics::const_deallocate(ptr.as_ptr(), layout.size(), layout.align());
}
const fn deallocate_nonzero_impl_const(ptr: NonNull<u8>, layout: Layout) {
// SAFETY: all conditions must be upheld by the caller
unsafe {
core::intrinsics::const_deallocate(ptr.as_ptr(), layout.size(), layout.align());
}
}

Expand All @@ -434,7 +430,7 @@ impl Global {
);
}
unsafe {
self.deallocate_impl(ptr, old_layout);
self.deallocate(ptr, old_layout);
}
Ok(new_ptr)
}
Expand All @@ -458,8 +454,17 @@ unsafe impl const Allocator for Global {
#[inline]
#[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
unsafe fn deallocate(&self, ptr: NonNull<u8>, layout: Layout) {
if layout.size() != 0 {
// SAFETY: We checked for nonzero size; other preconditions must be upheld by caller.
unsafe { self.deallocate_nonzero_size(ptr, layout) }
}
}

#[inline]
#[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
unsafe fn deallocate_nonzero_size(&self, ptr: NonNull<u8>, layout: Layout) {
// SAFETY: all conditions must be upheld by the caller
unsafe { self.deallocate_impl(ptr, layout) }
unsafe { self.deallocate_nonzero_impl(ptr, layout) }
}

#[inline]
Expand Down
2 changes: 1 addition & 1 deletion library/alloc/src/boxed.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1953,7 +1953,7 @@ unsafe impl<#[may_dangle] T: ?Sized, A: Allocator> Drop for Box<T, A> {
unsafe {
let layout = Layout::for_value_raw(ptr.as_ptr());
if layout.size() != 0 {
self.1.deallocate(From::from(ptr.cast()), layout);
self.1.deallocate_nonzero_size(From::from(ptr.cast()), layout);
}
}
}
Expand Down
16 changes: 9 additions & 7 deletions library/core/src/alloc/layout.rs
Original file line number Diff line number Diff line change
Expand Up @@ -215,9 +215,8 @@ impl Layout {
#[must_use]
#[inline]
pub const fn for_value<T: ?Sized>(t: &T) -> Self {
let (size, alignment) = (size_of_val(t), Alignment::of_val(t));
// SAFETY: see rationale in `new` for why this is using the unsafe variant
unsafe { Layout::from_size_alignment_unchecked(size, alignment) }
// SAFETY: Because `t` is a reference, its metadata is valid for this.
unsafe { Layout::for_value_raw(t) }
}

/// Produces layout describing a record that could be used to
Expand Down Expand Up @@ -250,11 +249,14 @@ impl Layout {
#[unstable(feature = "layout_for_ptr", issue = "69835")]
#[must_use]
#[inline]
pub const unsafe fn for_value_raw<T: ?Sized>(t: *const T) -> Self {
pub const unsafe fn for_value_raw<T: ?Sized>(ptr: *const T) -> Self {
// SAFETY: we pass along the prerequisites of these functions to the caller
let (size, alignment) = unsafe { (mem::size_of_val_raw(t), Alignment::of_val_raw(t)) };
// SAFETY: see rationale in `new` for why this is using the unsafe variant
unsafe { Layout::from_size_alignment_unchecked(size, alignment) }
let (size, align) = unsafe { (mem::size_of_val_raw(ptr), Alignment::of_val_raw(ptr)) };
// SAFETY: the dynamic size is that of a valid rust type, and those always
// meet the rules of `Layout` (just like in `Layout::new`).
// NB: We use a struct literal, instead of the unsafe constructor,
// to avoid the unnecessary UB check that has compile-time impact.
Layout { size, align }
}

/// Creates a `NonNull` that is dangling, but well-aligned for this Layout.
Expand Down
16 changes: 16 additions & 0 deletions library/core/src/alloc/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -172,6 +172,22 @@ pub const unsafe trait Allocator {
/// [*fit*]: #memory-fitting
unsafe fn deallocate(&self, ptr: NonNull<u8>, layout: Layout);

/// Deallocates the memory referenced by `ptr`.
///
/// # Safety
///
/// * `ptr` must denote a block of memory [*currently allocated*] via this allocator, and
/// * `layout` must [*fit*] that block of memory, and
/// * `layout.size()` must be greater than zero.
///
/// [*currently allocated*]: #currently-allocated-memory
/// [*fit*]: #memory-fitting
#[inline]
unsafe fn deallocate_nonzero_size(&self, ptr: NonNull<u8>, layout: Layout) {
// SAFETY: all conditions must be upheld by the caller
unsafe { self.deallocate(ptr, layout) }
}

/// Attempts to extend the memory block.
///
/// Returns a new [`NonNull<[u8]>`][NonNull] containing a pointer and the actual size of the allocated
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 @@ -2797,7 +2797,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>() -> mem::Alignment;

/// The offset of a field inside a type.
///
Expand Down Expand Up @@ -2871,7 +2871,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) -> mem::Alignment;

#[rustc_intrinsic]
#[unstable(feature = "core_intrinsics", issue = "none")]
Expand Down
Loading
Loading