Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

make size_of_val and align_of_val const fns #50559

Closed
wants to merge 2 commits into from
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
49 changes: 49 additions & 0 deletions src/libcore/mem.rs
Original file line number Diff line number Diff line change
Expand Up @@ -338,6 +338,34 @@ pub const fn size_of<T>() -> usize {
/// ```
#[inline]
#[stable(feature = "rust1", since = "1.0.0")]
#[cfg(not(stage0))]
pub const fn size_of_val<T: ?Sized>(val: &T) -> usize {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If you want this PR to go through fast, you should be marking the function with #[rustc_const_unstable(feature = "const_size_of_val")] (and create a tracking issue)

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@oli-obk const fn features have no tracking issues for now, unfortunately. See #44644.

unsafe { intrinsics::size_of_val(val) }
}

/// Returns the size of the pointed-to value in bytes.
///
/// This is usually the same as `size_of::<T>()`. However, when `T` *has* no
/// statically known size, e.g. a slice [`[T]`][slice] or a [trait object],
/// then `size_of_val` can be used to get the dynamically-known size.
///
/// [slice]: ../../std/primitive.slice.html
/// [trait object]: ../../book/first-edition/trait-objects.html
///
/// # Examples
///
/// ```
/// use std::mem;
///
/// assert_eq!(4, mem::size_of_val(&5i32));
///
/// let x: [u8; 13] = [0; 13];
/// let y: &[u8] = &x;
/// assert_eq!(13, mem::size_of_val(y));
/// ```
#[inline]
#[stable(feature = "rust1", since = "1.0.0")]
#[cfg(stage0)]
pub fn size_of_val<T: ?Sized>(val: &T) -> usize {
unsafe { intrinsics::size_of_val(val) }
}
Expand Down Expand Up @@ -422,10 +450,31 @@ pub const fn align_of<T>() -> usize {
/// ```
#[inline]
#[stable(feature = "rust1", since = "1.0.0")]
#[cfg(stage0)]
pub fn align_of_val<T: ?Sized>(val: &T) -> usize {
unsafe { intrinsics::min_align_of_val(val) }
}

/// Returns the [ABI]-required minimum alignment of the type of the value that `val` points to.
///
/// Every reference to a value of the type `T` must be a multiple of this number.
///
/// [ABI]: https://en.wikipedia.org/wiki/Application_binary_interface
///
/// # Examples
///
/// ```
/// use std::mem;
///
/// assert_eq!(4, mem::align_of_val(&5i32));
/// ```
#[inline]
#[stable(feature = "rust1", since = "1.0.0")]
#[cfg(not(stage0))]
pub const fn align_of_val<T: ?Sized>(val: &T) -> usize {
unsafe { intrinsics::min_align_of_val(val) }
}

/// Returns whether dropping values of type `T` matters.
///
/// This is purely an optimization hint, and may be implemented conservatively:
Expand Down
41 changes: 41 additions & 0 deletions src/libcore/tests/mem.rs
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,36 @@ fn size_of_val_basic() {
assert_eq!(size_of_val(&1u64), 8);
}

#[test]
fn size_of_val_const() {
macro_rules! ez_byte_string {
($name: ident, $string: expr) => {
static $name: [u8; size_of_val($string)] = *$string;
}
}

ez_byte_string!(OWO, b"what's this?");
ez_byte_string!(EMPTY, b"");

assert_eq!(&OWO, b"what's this?");
assert_eq!(&EMPTY, b"");

// ~ one day ~
// static SIZE_OF_OWO_SLICE: usize = size_of_val(&OWO[..]);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

you should be able to write

static FOO: &[u8] = &OWO;
static BAR: usize = size_of_val(FOO);

because coercions don't need method calls like slice indexing does

// static SIZE_OF_EMPTY_SLICE: usize = size_of_val(&EMPTY[..]);

// assert_eq!(SIZE_OF_OWO_SLICE, OWO.len());
// assert_eq!(SIZE_OF_EMPTY_SLICE, EMPTY.len());

const SIZE_OF_U8: usize = size_of_val(&0u8);
const SIZE_OF_U16: usize = size_of_val(&1u16);
static SIZE_OF_U32: usize = size_of_val(&9u32);

assert_eq!(SIZE_OF_U8, 1);
assert_eq!(SIZE_OF_U16, 2);
assert_eq!(SIZE_OF_U32, 4);
}

#[test]
fn align_of_basic() {
assert_eq!(align_of::<u8>(), 1);
Expand Down Expand Up @@ -82,6 +112,17 @@ fn align_of_val_basic() {
assert_eq!(align_of_val(&1u32), 4);
}

#[test]
fn align_of_val_const() {
const ALIGN_OF_U8: usize = align_of_val(&0u8);
const ALIGN_OF_U16: usize = align_of_val(&1u16);
static ALIGN_OF_U32: usize = align_of_val(&9u32);

assert_eq!(ALIGN_OF_U8, 1);
assert_eq!(ALIGN_OF_U16, 2);
assert_eq!(ALIGN_OF_U32, 4);
}

#[test]
fn test_swap() {
let mut x = 31337;
Expand Down
21 changes: 20 additions & 1 deletion src/librustc_mir/interpret/const_eval.rs
Original file line number Diff line number Diff line change
Expand Up @@ -256,7 +256,7 @@ impl<'mir, 'tcx> super::Machine<'mir, 'tcx> for CompileTimeEvaluator {
fn call_intrinsic<'a>(
ecx: &mut EvalContext<'a, 'mir, 'tcx, Self>,
instance: ty::Instance<'tcx>,
_args: &[ValTy<'tcx>],
args: &[ValTy<'tcx>],
dest: Place,
dest_layout: layout::TyLayout<'tcx>,
target: mir::BasicBlock,
Expand All @@ -272,12 +272,31 @@ impl<'mir, 'tcx> super::Machine<'mir, 'tcx> for CompileTimeEvaluator {
ecx.write_primval(dest, align_val, dest_layout.ty)?;
}

"min_align_of_val" => {
let ty = substs.type_at(0);
let (_, align) = ecx.size_and_align_of_dst(ty, args[0].value)?;
ecx.write_primval(
dest,
PrimVal::from_u128(align.abi() as u128),
dest_layout.ty,
)?;
}

"size_of" => {
let ty = substs.type_at(0);
let size = ecx.layout_of(ty)?.size.bytes() as u128;
ecx.write_primval(dest, PrimVal::from_u128(size), dest_layout.ty)?;
}

"size_of_val" => {
let ty = substs.type_at(0);
let (size, _) = ecx.size_and_align_of_dst(ty, args[0].value)?;
ecx.write_primval(
dest,
PrimVal::from_u128(size.bytes() as u128),
dest_layout.ty)?;
}

"type_id" => {
let ty = substs.type_at(0);
let type_id = ecx.tcx.type_id_hash(ty) as u128;
Expand Down
6 changes: 5 additions & 1 deletion src/librustc_mir/transform/qualify_consts.rs
Original file line number Diff line number Diff line change
Expand Up @@ -869,7 +869,11 @@ This does not pose a problem by itself because they can't be accessed directly."
Abi::PlatformIntrinsic => {
assert!(!self.tcx.is_const_fn(def_id));
match &self.tcx.item_name(def_id).as_str()[..] {
"size_of" | "min_align_of" | "type_id" => is_const_fn = Some(def_id),
"size_of" |
"size_of_val" |
"min_align_of" |
"min_align_of_val" |
"type_id" => is_const_fn = Some(def_id),

name if name.starts_with("simd_shuffle") => {
is_shuffle = true;
Expand Down