diff --git a/src/helpers.rs b/src/helpers.rs index 107a2551995a..5b820218a9dd 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -1,3 +1,5 @@ +pub mod convert; + use std::mem; use std::num::NonZeroUsize; use std::time::Duration; diff --git a/src/helpers/convert.rs b/src/helpers/convert.rs new file mode 100644 index 000000000000..4506fe47495d --- /dev/null +++ b/src/helpers/convert.rs @@ -0,0 +1,49 @@ +use implementations::NarrowerThan; + +/// Replacement for `as` casts going from wide integer to narrower integer. +/// +/// # Example +/// +/// ```ignore +/// let x = 99_u64; +/// let lo = x.truncate::(); +/// // lo is of type u16, equivalent to `x as u16`. +/// ``` +pub(crate) trait Truncate: Sized { + fn truncate(self) -> To + where + To: NarrowerThan, + { + NarrowerThan::truncate_from(self) + } +} + +impl Truncate for u16 {} +impl Truncate for u32 {} +impl Truncate for u64 {} +impl Truncate for u128 {} + +mod implementations { + pub(crate) trait NarrowerThan { + fn truncate_from(wide: T) -> Self; + } + + macro_rules! impl_narrower_than { + ($(NarrowerThan<{$($ty:ty),*}> for $self:ty)*) => { + $($( + impl NarrowerThan<$ty> for $self { + fn truncate_from(wide: $ty) -> Self { + wide as Self + } + } + )*)* + }; + } + + impl_narrower_than! { + NarrowerThan<{u128, u64, u32, u16}> for u8 + NarrowerThan<{u128, u64, u32}> for u16 + NarrowerThan<{u128, u64}> for u32 + NarrowerThan<{u128}> for u64 + } +} diff --git a/src/shims/foreign_items.rs b/src/shims/foreign_items.rs index ba4e384846be..e9845c537663 100644 --- a/src/shims/foreign_items.rs +++ b/src/shims/foreign_items.rs @@ -22,6 +22,7 @@ use rustc_target::{ }; use super::backtrace::EvalContextExt as _; +use crate::helpers::convert::Truncate; use crate::*; /// Returned by `emulate_foreign_item_by_name`. @@ -677,8 +678,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let a = this.read_scalar(a)?.to_u64()?; let b = this.read_scalar(b)?.to_u64()?; - let wide_sum = c_in as u128 + a as u128 + b as u128; - let (c_out, sum) = ((wide_sum >> 64) as u8, wide_sum as u64); + let wide_sum = u128::from(c_in) + u128::from(a) + u128::from(b); + let (c_out, sum) = ((wide_sum >> 64).truncate::(), wide_sum.truncate::()); let c_out_field = this.place_field(dest, 0)?; this.write_scalar(Scalar::from_u8(c_out), &c_out_field)?;