From db881914531d8731cdf537612fdef0b70401a8b8 Mon Sep 17 00:00:00 2001 From: Alexis Beingessner Date: Wed, 9 May 2018 02:24:40 -0400 Subject: [PATCH 1/2] make size_of_val and align_of_val const fns --- src/libcore/mem.rs | 49 ++++++++++++++++++++ src/librustc_mir/interpret/const_eval.rs | 21 ++++++++- src/librustc_mir/transform/qualify_consts.rs | 6 ++- 3 files changed, 74 insertions(+), 2 deletions(-) diff --git a/src/libcore/mem.rs b/src/libcore/mem.rs index 6cbe26afae9eb..004102279a07f 100644 --- a/src/libcore/mem.rs +++ b/src/libcore/mem.rs @@ -338,6 +338,34 @@ pub const fn size_of() -> usize { /// ``` #[inline] #[stable(feature = "rust1", since = "1.0.0")] +#[cfg(not(stage0))] +pub const fn size_of_val(val: &T) -> usize { + unsafe { intrinsics::size_of_val(val) } +} + +/// Returns the size of the pointed-to value in bytes. +/// +/// This is usually the same as `size_of::()`. 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(val: &T) -> usize { unsafe { intrinsics::size_of_val(val) } } @@ -422,10 +450,31 @@ pub const fn align_of() -> usize { /// ``` #[inline] #[stable(feature = "rust1", since = "1.0.0")] +#[cfg(stage0)] pub fn align_of_val(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(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: diff --git a/src/librustc_mir/interpret/const_eval.rs b/src/librustc_mir/interpret/const_eval.rs index dff9fa271aba5..9abeb2e5b1427 100644 --- a/src/librustc_mir/interpret/const_eval.rs +++ b/src/librustc_mir/interpret/const_eval.rs @@ -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, @@ -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; diff --git a/src/librustc_mir/transform/qualify_consts.rs b/src/librustc_mir/transform/qualify_consts.rs index 4762c6aaa27cc..92e3511b1235b 100644 --- a/src/librustc_mir/transform/qualify_consts.rs +++ b/src/librustc_mir/transform/qualify_consts.rs @@ -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; From 4d78e965ef969987375cfb78cf1db7dbc8d71d37 Mon Sep 17 00:00:00 2001 From: Alexis Beingessner Date: Wed, 9 May 2018 02:25:41 -0400 Subject: [PATCH 2/2] test const eval of size_of_val and align_of_val --- src/libcore/tests/mem.rs | 41 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 41 insertions(+) diff --git a/src/libcore/tests/mem.rs b/src/libcore/tests/mem.rs index f55a1c81463f7..cd159c317b644 100644 --- a/src/libcore/tests/mem.rs +++ b/src/libcore/tests/mem.rs @@ -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[..]); + // 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::(), 1); @@ -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;