Auto merge of #134830 - matthiaskrgr:rollup-7hdjojz, r=matthiaskrgr
Rollup of 6 pull requests Successful merges: - #133663 (Add a compiler intrinsic to back `bigint_helper_methods`) - #134798 (Make `ty::Error` implement all auto traits) - #134808 (compiletest: Remove empty 'expected' files when blessing) - #134809 (Add `--no-capture`/`--nocapture` as bootstrap arguments) - #134826 (Add spastorino to users_on_vacation) - #134828 (Add clubby789 back to bootstrap review rotation) r? `@ghost` `@rustbot` modify labels: rollup
This commit is contained in:
commit
dd84b7d5ee
34 changed files with 665 additions and 177 deletions
|
|
@ -340,6 +340,37 @@ impl<'ll, 'tcx> IntrinsicCallBuilderMethods<'tcx> for Builder<'_, 'll, 'tcx> {
|
||||||
self.const_i32(cache_type),
|
self.const_i32(cache_type),
|
||||||
])
|
])
|
||||||
}
|
}
|
||||||
|
sym::carrying_mul_add => {
|
||||||
|
let (size, signed) = fn_args.type_at(0).int_size_and_signed(self.tcx);
|
||||||
|
|
||||||
|
let wide_llty = self.type_ix(size.bits() * 2);
|
||||||
|
let args = args.as_array().unwrap();
|
||||||
|
let [a, b, c, d] = args.map(|a| self.intcast(a.immediate(), wide_llty, signed));
|
||||||
|
|
||||||
|
let wide = if signed {
|
||||||
|
let prod = self.unchecked_smul(a, b);
|
||||||
|
let acc = self.unchecked_sadd(prod, c);
|
||||||
|
self.unchecked_sadd(acc, d)
|
||||||
|
} else {
|
||||||
|
let prod = self.unchecked_umul(a, b);
|
||||||
|
let acc = self.unchecked_uadd(prod, c);
|
||||||
|
self.unchecked_uadd(acc, d)
|
||||||
|
};
|
||||||
|
|
||||||
|
let narrow_llty = self.type_ix(size.bits());
|
||||||
|
let low = self.trunc(wide, narrow_llty);
|
||||||
|
let bits_const = self.const_uint(wide_llty, size.bits());
|
||||||
|
// No need for ashr when signed; LLVM changes it to lshr anyway.
|
||||||
|
let high = self.lshr(wide, bits_const);
|
||||||
|
// FIXME: could be `trunc nuw`, even for signed.
|
||||||
|
let high = self.trunc(high, narrow_llty);
|
||||||
|
|
||||||
|
let pair_llty = self.type_struct(&[narrow_llty, narrow_llty], false);
|
||||||
|
let pair = self.const_poison(pair_llty);
|
||||||
|
let pair = self.insert_value(pair, low, 0);
|
||||||
|
let pair = self.insert_value(pair, high, 1);
|
||||||
|
pair
|
||||||
|
}
|
||||||
sym::ctlz
|
sym::ctlz
|
||||||
| sym::ctlz_nonzero
|
| sym::ctlz_nonzero
|
||||||
| sym::cttz
|
| sym::cttz
|
||||||
|
|
|
||||||
|
|
@ -17,6 +17,7 @@
|
||||||
#![feature(iter_intersperse)]
|
#![feature(iter_intersperse)]
|
||||||
#![feature(let_chains)]
|
#![feature(let_chains)]
|
||||||
#![feature(rustdoc_internals)]
|
#![feature(rustdoc_internals)]
|
||||||
|
#![feature(slice_as_array)]
|
||||||
#![feature(try_blocks)]
|
#![feature(try_blocks)]
|
||||||
#![warn(unreachable_pub)]
|
#![warn(unreachable_pub)]
|
||||||
// tidy-alphabetical-end
|
// tidy-alphabetical-end
|
||||||
|
|
|
||||||
|
|
@ -94,6 +94,7 @@ pub fn intrinsic_operation_unsafety(tcx: TyCtxt<'_>, intrinsic_id: LocalDefId) -
|
||||||
| sym::add_with_overflow
|
| sym::add_with_overflow
|
||||||
| sym::sub_with_overflow
|
| sym::sub_with_overflow
|
||||||
| sym::mul_with_overflow
|
| sym::mul_with_overflow
|
||||||
|
| sym::carrying_mul_add
|
||||||
| sym::wrapping_add
|
| sym::wrapping_add
|
||||||
| sym::wrapping_sub
|
| sym::wrapping_sub
|
||||||
| sym::wrapping_mul
|
| sym::wrapping_mul
|
||||||
|
|
@ -436,6 +437,10 @@ pub fn check_intrinsic_type(
|
||||||
(1, 0, vec![param(0), param(0)], Ty::new_tup(tcx, &[param(0), tcx.types.bool]))
|
(1, 0, vec![param(0), param(0)], Ty::new_tup(tcx, &[param(0), tcx.types.bool]))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
sym::carrying_mul_add => {
|
||||||
|
(2, 0, vec![param(0); 4], Ty::new_tup(tcx, &[param(1), param(0)]))
|
||||||
|
}
|
||||||
|
|
||||||
sym::ptr_guaranteed_cmp => (
|
sym::ptr_guaranteed_cmp => (
|
||||||
1,
|
1,
|
||||||
0,
|
0,
|
||||||
|
|
|
||||||
|
|
@ -555,6 +555,7 @@ symbols! {
|
||||||
call_ref_future,
|
call_ref_future,
|
||||||
caller_location,
|
caller_location,
|
||||||
capture_disjoint_fields,
|
capture_disjoint_fields,
|
||||||
|
carrying_mul_add,
|
||||||
catch_unwind,
|
catch_unwind,
|
||||||
cause,
|
cause,
|
||||||
cdylib,
|
cdylib,
|
||||||
|
|
|
||||||
|
|
@ -819,7 +819,9 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
||||||
candidates.vec.push(AutoImplCandidate)
|
candidates.vec.push(AutoImplCandidate)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ty::Error(_) => {} // do not add an auto trait impl for `ty::Error` for now.
|
ty::Error(_) => {
|
||||||
|
candidates.vec.push(AutoImplCandidate);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
111
library/core/src/intrinsics/fallback.rs
Normal file
111
library/core/src/intrinsics/fallback.rs
Normal file
|
|
@ -0,0 +1,111 @@
|
||||||
|
#![unstable(
|
||||||
|
feature = "core_intrinsics_fallbacks",
|
||||||
|
reason = "The fallbacks will never be stable, as they exist only to be called \
|
||||||
|
by the fallback MIR, but they're exported so they can be tested on \
|
||||||
|
platforms where the fallback MIR isn't actually used",
|
||||||
|
issue = "none"
|
||||||
|
)]
|
||||||
|
#![allow(missing_docs)]
|
||||||
|
|
||||||
|
#[const_trait]
|
||||||
|
pub trait CarryingMulAdd: Copy + 'static {
|
||||||
|
type Unsigned: Copy + 'static;
|
||||||
|
fn carrying_mul_add(
|
||||||
|
self,
|
||||||
|
multiplicand: Self,
|
||||||
|
addend: Self,
|
||||||
|
carry: Self,
|
||||||
|
) -> (Self::Unsigned, Self);
|
||||||
|
}
|
||||||
|
|
||||||
|
macro_rules! impl_carrying_mul_add_by_widening {
|
||||||
|
($($t:ident $u:ident $w:ident,)+) => {$(
|
||||||
|
#[rustc_const_unstable(feature = "core_intrinsics_fallbacks", issue = "none")]
|
||||||
|
impl const CarryingMulAdd for $t {
|
||||||
|
type Unsigned = $u;
|
||||||
|
#[inline]
|
||||||
|
fn carrying_mul_add(self, a: Self, b: Self, c: Self) -> ($u, $t) {
|
||||||
|
let wide = (self as $w) * (a as $w) + (b as $w) + (c as $w);
|
||||||
|
(wide as _, (wide >> Self::BITS) as _)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)+};
|
||||||
|
}
|
||||||
|
impl_carrying_mul_add_by_widening! {
|
||||||
|
u8 u8 u16,
|
||||||
|
u16 u16 u32,
|
||||||
|
u32 u32 u64,
|
||||||
|
u64 u64 u128,
|
||||||
|
usize usize UDoubleSize,
|
||||||
|
i8 u8 i16,
|
||||||
|
i16 u16 i32,
|
||||||
|
i32 u32 i64,
|
||||||
|
i64 u64 i128,
|
||||||
|
isize usize UDoubleSize,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(target_pointer_width = "16")]
|
||||||
|
type UDoubleSize = u32;
|
||||||
|
#[cfg(target_pointer_width = "32")]
|
||||||
|
type UDoubleSize = u64;
|
||||||
|
#[cfg(target_pointer_width = "64")]
|
||||||
|
type UDoubleSize = u128;
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
const fn wide_mul_u128(a: u128, b: u128) -> (u128, u128) {
|
||||||
|
#[inline]
|
||||||
|
const fn to_low_high(x: u128) -> [u128; 2] {
|
||||||
|
const MASK: u128 = u64::MAX as _;
|
||||||
|
[x & MASK, x >> 64]
|
||||||
|
}
|
||||||
|
#[inline]
|
||||||
|
const fn from_low_high(x: [u128; 2]) -> u128 {
|
||||||
|
x[0] | (x[1] << 64)
|
||||||
|
}
|
||||||
|
#[inline]
|
||||||
|
const fn scalar_mul(low_high: [u128; 2], k: u128) -> [u128; 3] {
|
||||||
|
let [x, c] = to_low_high(k * low_high[0]);
|
||||||
|
let [y, z] = to_low_high(k * low_high[1] + c);
|
||||||
|
[x, y, z]
|
||||||
|
}
|
||||||
|
let a = to_low_high(a);
|
||||||
|
let b = to_low_high(b);
|
||||||
|
let low = scalar_mul(a, b[0]);
|
||||||
|
let high = scalar_mul(a, b[1]);
|
||||||
|
let r0 = low[0];
|
||||||
|
let [r1, c] = to_low_high(low[1] + high[0]);
|
||||||
|
let [r2, c] = to_low_high(low[2] + high[1] + c);
|
||||||
|
let r3 = high[2] + c;
|
||||||
|
(from_low_high([r0, r1]), from_low_high([r2, r3]))
|
||||||
|
}
|
||||||
|
|
||||||
|
#[rustc_const_unstable(feature = "core_intrinsics_fallbacks", issue = "none")]
|
||||||
|
impl const CarryingMulAdd for u128 {
|
||||||
|
type Unsigned = u128;
|
||||||
|
#[inline]
|
||||||
|
fn carrying_mul_add(self, b: u128, c: u128, d: u128) -> (u128, u128) {
|
||||||
|
let (low, mut high) = wide_mul_u128(self, b);
|
||||||
|
let (low, carry) = u128::overflowing_add(low, c);
|
||||||
|
high += carry as u128;
|
||||||
|
let (low, carry) = u128::overflowing_add(low, d);
|
||||||
|
high += carry as u128;
|
||||||
|
(low, high)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[rustc_const_unstable(feature = "core_intrinsics_fallbacks", issue = "none")]
|
||||||
|
impl const CarryingMulAdd for i128 {
|
||||||
|
type Unsigned = u128;
|
||||||
|
#[inline]
|
||||||
|
fn carrying_mul_add(self, b: i128, c: i128, d: i128) -> (u128, i128) {
|
||||||
|
let (low, high) = wide_mul_u128(self as u128, b as u128);
|
||||||
|
let mut high = high as i128;
|
||||||
|
high = high.wrapping_add(i128::wrapping_mul(self >> 127, b));
|
||||||
|
high = high.wrapping_add(i128::wrapping_mul(self, b >> 127));
|
||||||
|
let (low, carry) = u128::overflowing_add(low, c as u128);
|
||||||
|
high = high.wrapping_add((carry as i128) + (c >> 127));
|
||||||
|
let (low, carry) = u128::overflowing_add(low, d as u128);
|
||||||
|
high = high.wrapping_add((carry as i128) + (d >> 127));
|
||||||
|
(low, high)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -68,6 +68,7 @@ use crate::marker::{DiscriminantKind, Tuple};
|
||||||
use crate::mem::SizedTypeProperties;
|
use crate::mem::SizedTypeProperties;
|
||||||
use crate::{ptr, ub_checks};
|
use crate::{ptr, ub_checks};
|
||||||
|
|
||||||
|
pub mod fallback;
|
||||||
pub mod mir;
|
pub mod mir;
|
||||||
pub mod simd;
|
pub mod simd;
|
||||||
|
|
||||||
|
|
@ -3305,6 +3306,34 @@ pub const fn mul_with_overflow<T: Copy>(_x: T, _y: T) -> (T, bool) {
|
||||||
unimplemented!()
|
unimplemented!()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Performs full-width multiplication and addition with a carry:
|
||||||
|
/// `multiplier * multiplicand + addend + carry`.
|
||||||
|
///
|
||||||
|
/// This is possible without any overflow. For `uN`:
|
||||||
|
/// MAX * MAX + MAX + MAX
|
||||||
|
/// => (2ⁿ-1) × (2ⁿ-1) + (2ⁿ-1) + (2ⁿ-1)
|
||||||
|
/// => (2²ⁿ - 2ⁿ⁺¹ + 1) + (2ⁿ⁺¹ - 2)
|
||||||
|
/// => 2²ⁿ - 1
|
||||||
|
///
|
||||||
|
/// For `iN`, the upper bound is MIN * MIN + MAX + MAX => 2²ⁿ⁻² + 2ⁿ - 2,
|
||||||
|
/// and the lower bound is MAX * MIN + MIN + MIN => -2²ⁿ⁻² - 2ⁿ + 2ⁿ⁺¹.
|
||||||
|
///
|
||||||
|
/// This currently supports unsigned integers *only*, no signed ones.
|
||||||
|
/// The stabilized versions of this intrinsic are available on integers.
|
||||||
|
#[unstable(feature = "core_intrinsics", issue = "none")]
|
||||||
|
#[rustc_const_unstable(feature = "const_carrying_mul_add", issue = "85532")]
|
||||||
|
#[rustc_nounwind]
|
||||||
|
#[cfg_attr(not(bootstrap), rustc_intrinsic)]
|
||||||
|
#[cfg_attr(not(bootstrap), miri::intrinsic_fallback_is_spec)]
|
||||||
|
pub const fn carrying_mul_add<T: ~const fallback::CarryingMulAdd<Unsigned = U>, U>(
|
||||||
|
multiplier: T,
|
||||||
|
multiplicand: T,
|
||||||
|
addend: T,
|
||||||
|
carry: T,
|
||||||
|
) -> (U, T) {
|
||||||
|
multiplier.carrying_mul_add(multiplicand, addend, carry)
|
||||||
|
}
|
||||||
|
|
||||||
/// Performs an exact division, resulting in undefined behavior where
|
/// Performs an exact division, resulting in undefined behavior where
|
||||||
/// `x % y != 0` or `y == 0` or `x == T::MIN && y == -1`
|
/// `x % y != 0` or `y == 0` or `x == T::MIN && y == -1`
|
||||||
///
|
///
|
||||||
|
|
|
||||||
|
|
@ -110,6 +110,7 @@
|
||||||
#![cfg_attr(bootstrap, feature(do_not_recommend))]
|
#![cfg_attr(bootstrap, feature(do_not_recommend))]
|
||||||
#![feature(array_ptr_get)]
|
#![feature(array_ptr_get)]
|
||||||
#![feature(asm_experimental_arch)]
|
#![feature(asm_experimental_arch)]
|
||||||
|
#![feature(const_carrying_mul_add)]
|
||||||
#![feature(const_eval_select)]
|
#![feature(const_eval_select)]
|
||||||
#![feature(const_typed_swap)]
|
#![feature(const_typed_swap)]
|
||||||
#![feature(core_intrinsics)]
|
#![feature(core_intrinsics)]
|
||||||
|
|
|
||||||
|
|
@ -228,134 +228,6 @@ macro_rules! midpoint_impl {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
macro_rules! widening_impl {
|
|
||||||
($SelfT:ty, $WideT:ty, $BITS:literal, unsigned) => {
|
|
||||||
/// Calculates the complete product `self * rhs` without the possibility to overflow.
|
|
||||||
///
|
|
||||||
/// This returns the low-order (wrapping) bits and the high-order (overflow) bits
|
|
||||||
/// of the result as two separate values, in that order.
|
|
||||||
///
|
|
||||||
/// If you also need to add a carry to the wide result, then you want
|
|
||||||
/// [`Self::carrying_mul`] instead.
|
|
||||||
///
|
|
||||||
/// # Examples
|
|
||||||
///
|
|
||||||
/// Basic usage:
|
|
||||||
///
|
|
||||||
/// Please note that this example is shared between integer types.
|
|
||||||
/// Which explains why `u32` is used here.
|
|
||||||
///
|
|
||||||
/// ```
|
|
||||||
/// #![feature(bigint_helper_methods)]
|
|
||||||
/// assert_eq!(5u32.widening_mul(2), (10, 0));
|
|
||||||
/// assert_eq!(1_000_000_000u32.widening_mul(10), (1410065408, 2));
|
|
||||||
/// ```
|
|
||||||
#[unstable(feature = "bigint_helper_methods", issue = "85532")]
|
|
||||||
#[must_use = "this returns the result of the operation, \
|
|
||||||
without modifying the original"]
|
|
||||||
#[inline]
|
|
||||||
pub const fn widening_mul(self, rhs: Self) -> (Self, Self) {
|
|
||||||
// note: longer-term this should be done via an intrinsic,
|
|
||||||
// but for now we can deal without an impl for u128/i128
|
|
||||||
// SAFETY: overflow will be contained within the wider types
|
|
||||||
let wide = unsafe { (self as $WideT).unchecked_mul(rhs as $WideT) };
|
|
||||||
(wide as $SelfT, (wide >> $BITS) as $SelfT)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Calculates the "full multiplication" `self * rhs + carry`
|
|
||||||
/// without the possibility to overflow.
|
|
||||||
///
|
|
||||||
/// This returns the low-order (wrapping) bits and the high-order (overflow) bits
|
|
||||||
/// of the result as two separate values, in that order.
|
|
||||||
///
|
|
||||||
/// Performs "long multiplication" which takes in an extra amount to add, and may return an
|
|
||||||
/// additional amount of overflow. This allows for chaining together multiple
|
|
||||||
/// multiplications to create "big integers" which represent larger values.
|
|
||||||
///
|
|
||||||
/// If you don't need the `carry`, then you can use [`Self::widening_mul`] instead.
|
|
||||||
///
|
|
||||||
/// # Examples
|
|
||||||
///
|
|
||||||
/// Basic usage:
|
|
||||||
///
|
|
||||||
/// Please note that this example is shared between integer types.
|
|
||||||
/// Which explains why `u32` is used here.
|
|
||||||
///
|
|
||||||
/// ```
|
|
||||||
/// #![feature(bigint_helper_methods)]
|
|
||||||
/// assert_eq!(5u32.carrying_mul(2, 0), (10, 0));
|
|
||||||
/// assert_eq!(5u32.carrying_mul(2, 10), (20, 0));
|
|
||||||
/// assert_eq!(1_000_000_000u32.carrying_mul(10, 0), (1410065408, 2));
|
|
||||||
/// assert_eq!(1_000_000_000u32.carrying_mul(10, 10), (1410065418, 2));
|
|
||||||
#[doc = concat!("assert_eq!(",
|
|
||||||
stringify!($SelfT), "::MAX.carrying_mul(", stringify!($SelfT), "::MAX, ", stringify!($SelfT), "::MAX), ",
|
|
||||||
"(0, ", stringify!($SelfT), "::MAX));"
|
|
||||||
)]
|
|
||||||
/// ```
|
|
||||||
///
|
|
||||||
/// This is the core operation needed for scalar multiplication when
|
|
||||||
/// implementing it for wider-than-native types.
|
|
||||||
///
|
|
||||||
/// ```
|
|
||||||
/// #![feature(bigint_helper_methods)]
|
|
||||||
/// fn scalar_mul_eq(little_endian_digits: &mut Vec<u16>, multiplicand: u16) {
|
|
||||||
/// let mut carry = 0;
|
|
||||||
/// for d in little_endian_digits.iter_mut() {
|
|
||||||
/// (*d, carry) = d.carrying_mul(multiplicand, carry);
|
|
||||||
/// }
|
|
||||||
/// if carry != 0 {
|
|
||||||
/// little_endian_digits.push(carry);
|
|
||||||
/// }
|
|
||||||
/// }
|
|
||||||
///
|
|
||||||
/// let mut v = vec![10, 20];
|
|
||||||
/// scalar_mul_eq(&mut v, 3);
|
|
||||||
/// assert_eq!(v, [30, 60]);
|
|
||||||
///
|
|
||||||
/// assert_eq!(0x87654321_u64 * 0xFEED, 0x86D3D159E38D);
|
|
||||||
/// let mut v = vec![0x4321, 0x8765];
|
|
||||||
/// scalar_mul_eq(&mut v, 0xFEED);
|
|
||||||
/// assert_eq!(v, [0xE38D, 0xD159, 0x86D3]);
|
|
||||||
/// ```
|
|
||||||
///
|
|
||||||
/// If `carry` is zero, this is similar to [`overflowing_mul`](Self::overflowing_mul),
|
|
||||||
/// except that it gives the value of the overflow instead of just whether one happened:
|
|
||||||
///
|
|
||||||
/// ```
|
|
||||||
/// #![feature(bigint_helper_methods)]
|
|
||||||
/// let r = u8::carrying_mul(7, 13, 0);
|
|
||||||
/// assert_eq!((r.0, r.1 != 0), u8::overflowing_mul(7, 13));
|
|
||||||
/// let r = u8::carrying_mul(13, 42, 0);
|
|
||||||
/// assert_eq!((r.0, r.1 != 0), u8::overflowing_mul(13, 42));
|
|
||||||
/// ```
|
|
||||||
///
|
|
||||||
/// The value of the first field in the returned tuple matches what you'd get
|
|
||||||
/// by combining the [`wrapping_mul`](Self::wrapping_mul) and
|
|
||||||
/// [`wrapping_add`](Self::wrapping_add) methods:
|
|
||||||
///
|
|
||||||
/// ```
|
|
||||||
/// #![feature(bigint_helper_methods)]
|
|
||||||
/// assert_eq!(
|
|
||||||
/// 789_u16.carrying_mul(456, 123).0,
|
|
||||||
/// 789_u16.wrapping_mul(456).wrapping_add(123),
|
|
||||||
/// );
|
|
||||||
/// ```
|
|
||||||
#[unstable(feature = "bigint_helper_methods", issue = "85532")]
|
|
||||||
#[must_use = "this returns the result of the operation, \
|
|
||||||
without modifying the original"]
|
|
||||||
#[inline]
|
|
||||||
pub const fn carrying_mul(self, rhs: Self, carry: Self) -> (Self, Self) {
|
|
||||||
// note: longer-term this should be done via an intrinsic,
|
|
||||||
// but for now we can deal without an impl for u128/i128
|
|
||||||
// SAFETY: overflow will be contained within the wider types
|
|
||||||
let wide = unsafe {
|
|
||||||
(self as $WideT).unchecked_mul(rhs as $WideT).unchecked_add(carry as $WideT)
|
|
||||||
};
|
|
||||||
(wide as $SelfT, (wide >> $BITS) as $SelfT)
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
impl i8 {
|
impl i8 {
|
||||||
int_impl! {
|
int_impl! {
|
||||||
Self = i8,
|
Self = i8,
|
||||||
|
|
@ -576,7 +448,6 @@ impl u8 {
|
||||||
from_xe_bytes_doc = u8_xe_bytes_doc!(),
|
from_xe_bytes_doc = u8_xe_bytes_doc!(),
|
||||||
bound_condition = "",
|
bound_condition = "",
|
||||||
}
|
}
|
||||||
widening_impl! { u8, u16, 8, unsigned }
|
|
||||||
midpoint_impl! { u8, u16, unsigned }
|
midpoint_impl! { u8, u16, unsigned }
|
||||||
|
|
||||||
/// Checks if the value is within the ASCII range.
|
/// Checks if the value is within the ASCII range.
|
||||||
|
|
@ -1192,7 +1063,6 @@ impl u16 {
|
||||||
from_xe_bytes_doc = "",
|
from_xe_bytes_doc = "",
|
||||||
bound_condition = "",
|
bound_condition = "",
|
||||||
}
|
}
|
||||||
widening_impl! { u16, u32, 16, unsigned }
|
|
||||||
midpoint_impl! { u16, u32, unsigned }
|
midpoint_impl! { u16, u32, unsigned }
|
||||||
|
|
||||||
/// Checks if the value is a Unicode surrogate code point, which are disallowed values for [`char`].
|
/// Checks if the value is a Unicode surrogate code point, which are disallowed values for [`char`].
|
||||||
|
|
@ -1240,7 +1110,6 @@ impl u32 {
|
||||||
from_xe_bytes_doc = "",
|
from_xe_bytes_doc = "",
|
||||||
bound_condition = "",
|
bound_condition = "",
|
||||||
}
|
}
|
||||||
widening_impl! { u32, u64, 32, unsigned }
|
|
||||||
midpoint_impl! { u32, u64, unsigned }
|
midpoint_impl! { u32, u64, unsigned }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1264,7 +1133,6 @@ impl u64 {
|
||||||
from_xe_bytes_doc = "",
|
from_xe_bytes_doc = "",
|
||||||
bound_condition = "",
|
bound_condition = "",
|
||||||
}
|
}
|
||||||
widening_impl! { u64, u128, 64, unsigned }
|
|
||||||
midpoint_impl! { u64, u128, unsigned }
|
midpoint_impl! { u64, u128, unsigned }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1314,7 +1182,6 @@ impl usize {
|
||||||
from_xe_bytes_doc = usize_isize_from_xe_bytes_doc!(),
|
from_xe_bytes_doc = usize_isize_from_xe_bytes_doc!(),
|
||||||
bound_condition = " on 16-bit targets",
|
bound_condition = " on 16-bit targets",
|
||||||
}
|
}
|
||||||
widening_impl! { usize, u32, 16, unsigned }
|
|
||||||
midpoint_impl! { usize, u32, unsigned }
|
midpoint_impl! { usize, u32, unsigned }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1339,7 +1206,6 @@ impl usize {
|
||||||
from_xe_bytes_doc = usize_isize_from_xe_bytes_doc!(),
|
from_xe_bytes_doc = usize_isize_from_xe_bytes_doc!(),
|
||||||
bound_condition = " on 32-bit targets",
|
bound_condition = " on 32-bit targets",
|
||||||
}
|
}
|
||||||
widening_impl! { usize, u64, 32, unsigned }
|
|
||||||
midpoint_impl! { usize, u64, unsigned }
|
midpoint_impl! { usize, u64, unsigned }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1364,7 +1230,6 @@ impl usize {
|
||||||
from_xe_bytes_doc = usize_isize_from_xe_bytes_doc!(),
|
from_xe_bytes_doc = usize_isize_from_xe_bytes_doc!(),
|
||||||
bound_condition = " on 64-bit targets",
|
bound_condition = " on 64-bit targets",
|
||||||
}
|
}
|
||||||
widening_impl! { usize, u128, 64, unsigned }
|
|
||||||
midpoint_impl! { usize, u128, unsigned }
|
midpoint_impl! { usize, u128, unsigned }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -3347,6 +3347,122 @@ macro_rules! uint_impl {
|
||||||
unsafe { mem::transmute(bytes) }
|
unsafe { mem::transmute(bytes) }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Calculates the complete product `self * rhs` without the possibility to overflow.
|
||||||
|
///
|
||||||
|
/// This returns the low-order (wrapping) bits and the high-order (overflow) bits
|
||||||
|
/// of the result as two separate values, in that order.
|
||||||
|
///
|
||||||
|
/// If you also need to add a carry to the wide result, then you want
|
||||||
|
/// [`Self::carrying_mul`] instead.
|
||||||
|
///
|
||||||
|
/// # Examples
|
||||||
|
///
|
||||||
|
/// Basic usage:
|
||||||
|
///
|
||||||
|
/// Please note that this example is shared between integer types.
|
||||||
|
/// Which explains why `u32` is used here.
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// #![feature(bigint_helper_methods)]
|
||||||
|
/// assert_eq!(5u32.widening_mul(2), (10, 0));
|
||||||
|
/// assert_eq!(1_000_000_000u32.widening_mul(10), (1410065408, 2));
|
||||||
|
/// ```
|
||||||
|
#[unstable(feature = "bigint_helper_methods", issue = "85532")]
|
||||||
|
#[rustc_const_unstable(feature = "bigint_helper_methods", issue = "85532")]
|
||||||
|
#[must_use = "this returns the result of the operation, \
|
||||||
|
without modifying the original"]
|
||||||
|
#[inline]
|
||||||
|
pub const fn widening_mul(self, rhs: Self) -> (Self, Self) {
|
||||||
|
Self::carrying_mul(self, rhs, 0)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Calculates the "full multiplication" `self * rhs + carry`
|
||||||
|
/// without the possibility to overflow.
|
||||||
|
///
|
||||||
|
/// This returns the low-order (wrapping) bits and the high-order (overflow) bits
|
||||||
|
/// of the result as two separate values, in that order.
|
||||||
|
///
|
||||||
|
/// Performs "long multiplication" which takes in an extra amount to add, and may return an
|
||||||
|
/// additional amount of overflow. This allows for chaining together multiple
|
||||||
|
/// multiplications to create "big integers" which represent larger values.
|
||||||
|
///
|
||||||
|
/// If you don't need the `carry`, then you can use [`Self::widening_mul`] instead.
|
||||||
|
///
|
||||||
|
/// # Examples
|
||||||
|
///
|
||||||
|
/// Basic usage:
|
||||||
|
///
|
||||||
|
/// Please note that this example is shared between integer types.
|
||||||
|
/// Which explains why `u32` is used here.
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// #![feature(bigint_helper_methods)]
|
||||||
|
/// assert_eq!(5u32.carrying_mul(2, 0), (10, 0));
|
||||||
|
/// assert_eq!(5u32.carrying_mul(2, 10), (20, 0));
|
||||||
|
/// assert_eq!(1_000_000_000u32.carrying_mul(10, 0), (1410065408, 2));
|
||||||
|
/// assert_eq!(1_000_000_000u32.carrying_mul(10, 10), (1410065418, 2));
|
||||||
|
#[doc = concat!("assert_eq!(",
|
||||||
|
stringify!($SelfT), "::MAX.carrying_mul(", stringify!($SelfT), "::MAX, ", stringify!($SelfT), "::MAX), ",
|
||||||
|
"(0, ", stringify!($SelfT), "::MAX));"
|
||||||
|
)]
|
||||||
|
/// ```
|
||||||
|
///
|
||||||
|
/// This is the core operation needed for scalar multiplication when
|
||||||
|
/// implementing it for wider-than-native types.
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// #![feature(bigint_helper_methods)]
|
||||||
|
/// fn scalar_mul_eq(little_endian_digits: &mut Vec<u16>, multiplicand: u16) {
|
||||||
|
/// let mut carry = 0;
|
||||||
|
/// for d in little_endian_digits.iter_mut() {
|
||||||
|
/// (*d, carry) = d.carrying_mul(multiplicand, carry);
|
||||||
|
/// }
|
||||||
|
/// if carry != 0 {
|
||||||
|
/// little_endian_digits.push(carry);
|
||||||
|
/// }
|
||||||
|
/// }
|
||||||
|
///
|
||||||
|
/// let mut v = vec![10, 20];
|
||||||
|
/// scalar_mul_eq(&mut v, 3);
|
||||||
|
/// assert_eq!(v, [30, 60]);
|
||||||
|
///
|
||||||
|
/// assert_eq!(0x87654321_u64 * 0xFEED, 0x86D3D159E38D);
|
||||||
|
/// let mut v = vec![0x4321, 0x8765];
|
||||||
|
/// scalar_mul_eq(&mut v, 0xFEED);
|
||||||
|
/// assert_eq!(v, [0xE38D, 0xD159, 0x86D3]);
|
||||||
|
/// ```
|
||||||
|
///
|
||||||
|
/// If `carry` is zero, this is similar to [`overflowing_mul`](Self::overflowing_mul),
|
||||||
|
/// except that it gives the value of the overflow instead of just whether one happened:
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// #![feature(bigint_helper_methods)]
|
||||||
|
/// let r = u8::carrying_mul(7, 13, 0);
|
||||||
|
/// assert_eq!((r.0, r.1 != 0), u8::overflowing_mul(7, 13));
|
||||||
|
/// let r = u8::carrying_mul(13, 42, 0);
|
||||||
|
/// assert_eq!((r.0, r.1 != 0), u8::overflowing_mul(13, 42));
|
||||||
|
/// ```
|
||||||
|
///
|
||||||
|
/// The value of the first field in the returned tuple matches what you'd get
|
||||||
|
/// by combining the [`wrapping_mul`](Self::wrapping_mul) and
|
||||||
|
/// [`wrapping_add`](Self::wrapping_add) methods:
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// #![feature(bigint_helper_methods)]
|
||||||
|
/// assert_eq!(
|
||||||
|
/// 789_u16.carrying_mul(456, 123).0,
|
||||||
|
/// 789_u16.wrapping_mul(456).wrapping_add(123),
|
||||||
|
/// );
|
||||||
|
/// ```
|
||||||
|
#[unstable(feature = "bigint_helper_methods", issue = "85532")]
|
||||||
|
#[rustc_const_unstable(feature = "bigint_helper_methods", issue = "85532")]
|
||||||
|
#[must_use = "this returns the result of the operation, \
|
||||||
|
without modifying the original"]
|
||||||
|
#[inline]
|
||||||
|
pub const fn carrying_mul(self, rhs: Self, carry: Self) -> (Self, Self) {
|
||||||
|
intrinsics::carrying_mul_add(self, rhs, 0, carry)
|
||||||
|
}
|
||||||
|
|
||||||
/// New code should prefer to use
|
/// New code should prefer to use
|
||||||
#[doc = concat!("[`", stringify!($SelfT), "::MIN", "`] instead.")]
|
#[doc = concat!("[`", stringify!($SelfT), "::MIN", "`] instead.")]
|
||||||
///
|
///
|
||||||
|
|
|
||||||
|
|
@ -125,3 +125,71 @@ fn test_three_way_compare_in_const_contexts() {
|
||||||
assert_eq!(SIGNED_EQUAL, Equal);
|
assert_eq!(SIGNED_EQUAL, Equal);
|
||||||
assert_eq!(SIGNED_GREATER, Greater);
|
assert_eq!(SIGNED_GREATER, Greater);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn fallback_cma<T: core::intrinsics::fallback::CarryingMulAdd>(
|
||||||
|
a: T,
|
||||||
|
b: T,
|
||||||
|
c: T,
|
||||||
|
d: T,
|
||||||
|
) -> (T::Unsigned, T) {
|
||||||
|
a.carrying_mul_add(b, c, d)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn carrying_mul_add_fallback_u32() {
|
||||||
|
let r = fallback_cma::<u32>(0x9e37_79b9, 0x7f4a_7c15, 0xf39c_c060, 0x5ced_c834);
|
||||||
|
assert_eq!(r, (0x2087_20c1, 0x4eab_8e1d));
|
||||||
|
let r = fallback_cma::<u32>(0x1082_276b, 0xf3a2_7251, 0xf86c_6a11, 0xd0c1_8e95);
|
||||||
|
assert_eq!(r, (0x7aa0_1781, 0x0fb6_0528));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn carrying_mul_add_fallback_i32() {
|
||||||
|
let r = fallback_cma::<i32>(-1, -1, -1, -1);
|
||||||
|
assert_eq!(r, (u32::MAX, -1));
|
||||||
|
let r = fallback_cma::<i32>(1, -1, 1, 1);
|
||||||
|
assert_eq!(r, (1, 0));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn carrying_mul_add_fallback_u128() {
|
||||||
|
assert_eq!(fallback_cma::<u128>(u128::MAX, u128::MAX, 0, 0), (1, u128::MAX - 1));
|
||||||
|
assert_eq!(fallback_cma::<u128>(1, 1, 1, 1), (3, 0));
|
||||||
|
assert_eq!(fallback_cma::<u128>(0, 0, u128::MAX, u128::MAX), (u128::MAX - 1, 1));
|
||||||
|
assert_eq!(
|
||||||
|
fallback_cma::<u128>(u128::MAX, u128::MAX, u128::MAX, u128::MAX),
|
||||||
|
(u128::MAX, u128::MAX),
|
||||||
|
);
|
||||||
|
|
||||||
|
let r = fallback_cma::<u128>(
|
||||||
|
0x243f6a8885a308d313198a2e03707344,
|
||||||
|
0xa4093822299f31d0082efa98ec4e6c89,
|
||||||
|
0x452821e638d01377be5466cf34e90c6c,
|
||||||
|
0xc0ac29b7c97c50dd3f84d5b5b5470917,
|
||||||
|
);
|
||||||
|
assert_eq!(r, (0x8050ec20ed554e40338d277e00b674e7, 0x1739ee6cea07da409182d003859b59d8));
|
||||||
|
let r = fallback_cma::<u128>(
|
||||||
|
0x9216d5d98979fb1bd1310ba698dfb5ac,
|
||||||
|
0x2ffd72dbd01adfb7b8e1afed6a267e96,
|
||||||
|
0xba7c9045f12c7f9924a19947b3916cf7,
|
||||||
|
0x0801f2e2858efc16636920d871574e69,
|
||||||
|
);
|
||||||
|
assert_eq!(r, (0x185525545fdb2fefb502a3a602efd628, 0x1b62d35fe3bff6b566f99667ef7ebfd6));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn carrying_mul_add_fallback_i128() {
|
||||||
|
assert_eq!(fallback_cma::<i128>(-1, -1, 0, 0), (1, 0));
|
||||||
|
let r = fallback_cma::<i128>(-1, -1, -1, -1);
|
||||||
|
assert_eq!(r, (u128::MAX, -1));
|
||||||
|
let r = fallback_cma::<i128>(1, -1, 1, 1);
|
||||||
|
assert_eq!(r, (1, 0));
|
||||||
|
assert_eq!(
|
||||||
|
fallback_cma::<i128>(i128::MAX, i128::MAX, i128::MAX, i128::MAX),
|
||||||
|
(u128::MAX, i128::MAX / 2),
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
fallback_cma::<i128>(i128::MIN, i128::MIN, i128::MAX, i128::MAX),
|
||||||
|
(u128::MAX - 1, -(i128::MIN / 2)),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -19,6 +19,7 @@
|
||||||
#![feature(const_swap_nonoverlapping)]
|
#![feature(const_swap_nonoverlapping)]
|
||||||
#![feature(const_trait_impl)]
|
#![feature(const_trait_impl)]
|
||||||
#![feature(core_intrinsics)]
|
#![feature(core_intrinsics)]
|
||||||
|
#![feature(core_intrinsics_fallbacks)]
|
||||||
#![feature(core_io_borrowed_buf)]
|
#![feature(core_io_borrowed_buf)]
|
||||||
#![feature(core_private_bignum)]
|
#![feature(core_private_bignum)]
|
||||||
#![feature(core_private_diy_float)]
|
#![feature(core_private_diy_float)]
|
||||||
|
|
|
||||||
|
|
@ -1829,6 +1829,10 @@ NOTE: if you're sure you want to do this, please open an issue as to why. In the
|
||||||
cmd.arg("--force-rerun");
|
cmd.arg("--force-rerun");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if builder.config.cmd.no_capture() {
|
||||||
|
cmd.arg("--no-capture");
|
||||||
|
}
|
||||||
|
|
||||||
let compare_mode =
|
let compare_mode =
|
||||||
builder.config.cmd.compare_mode().or_else(|| {
|
builder.config.cmd.compare_mode().or_else(|| {
|
||||||
if builder.config.test_compare_mode { self.compare_mode } else { None }
|
if builder.config.test_compare_mode { self.compare_mode } else { None }
|
||||||
|
|
|
||||||
|
|
@ -637,6 +637,7 @@ mod dist {
|
||||||
run: None,
|
run: None,
|
||||||
only_modified: false,
|
only_modified: false,
|
||||||
extra_checks: None,
|
extra_checks: None,
|
||||||
|
no_capture: false,
|
||||||
};
|
};
|
||||||
|
|
||||||
let build = Build::new(config);
|
let build = Build::new(config);
|
||||||
|
|
@ -702,6 +703,7 @@ mod dist {
|
||||||
run: None,
|
run: None,
|
||||||
only_modified: false,
|
only_modified: false,
|
||||||
extra_checks: None,
|
extra_checks: None,
|
||||||
|
no_capture: false,
|
||||||
};
|
};
|
||||||
// Make sure rustfmt binary not being found isn't an error.
|
// Make sure rustfmt binary not being found isn't an error.
|
||||||
config.channel = "beta".to_string();
|
config.channel = "beta".to_string();
|
||||||
|
|
|
||||||
|
|
@ -388,6 +388,9 @@ pub enum Subcommand {
|
||||||
/// enable this to generate a Rustfix coverage file, which is saved in
|
/// enable this to generate a Rustfix coverage file, which is saved in
|
||||||
/// `/<build_base>/rustfix_missing_coverage.txt`
|
/// `/<build_base>/rustfix_missing_coverage.txt`
|
||||||
rustfix_coverage: bool,
|
rustfix_coverage: bool,
|
||||||
|
#[arg(long)]
|
||||||
|
/// don't capture stdout/stderr of tests
|
||||||
|
no_capture: bool,
|
||||||
},
|
},
|
||||||
/// Build and run some test suites *in Miri*
|
/// Build and run some test suites *in Miri*
|
||||||
Miri {
|
Miri {
|
||||||
|
|
@ -563,6 +566,13 @@ impl Subcommand {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn no_capture(&self) -> bool {
|
||||||
|
match *self {
|
||||||
|
Subcommand::Test { no_capture, .. } => no_capture,
|
||||||
|
_ => false,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn rustfix_coverage(&self) -> bool {
|
pub fn rustfix_coverage(&self) -> bool {
|
||||||
match *self {
|
match *self {
|
||||||
Subcommand::Test { rustfix_coverage, .. } => rustfix_coverage,
|
Subcommand::Test { rustfix_coverage, .. } => rustfix_coverage,
|
||||||
|
|
|
||||||
|
|
@ -315,4 +315,9 @@ pub const CONFIG_CHANGE_HISTORY: &[ChangeInfo] = &[
|
||||||
severity: ChangeSeverity::Info,
|
severity: ChangeSeverity::Info,
|
||||||
summary: "`build.vendor` is now enabled by default for dist/tarball sources when 'vendor' directory and '.cargo/config.toml' file are present.",
|
summary: "`build.vendor` is now enabled by default for dist/tarball sources when 'vendor' directory and '.cargo/config.toml' file are present.",
|
||||||
},
|
},
|
||||||
|
ChangeInfo {
|
||||||
|
change_id: 134809,
|
||||||
|
severity: ChangeSeverity::Warning,
|
||||||
|
summary: "compiletest now takes `--no-capture` instead of `--nocapture`; bootstrap now accepts `--no-capture` as an argument to test commands directly",
|
||||||
|
},
|
||||||
];
|
];
|
||||||
|
|
|
||||||
|
|
@ -319,6 +319,7 @@ complete -c x -n "__fish_x_using_subcommand test" -l bless -d 'whether to automa
|
||||||
complete -c x -n "__fish_x_using_subcommand test" -l force-rerun -d 'rerun tests even if the inputs are unchanged'
|
complete -c x -n "__fish_x_using_subcommand test" -l force-rerun -d 'rerun tests even if the inputs are unchanged'
|
||||||
complete -c x -n "__fish_x_using_subcommand test" -l only-modified -d 'only run tests that result has been changed'
|
complete -c x -n "__fish_x_using_subcommand test" -l only-modified -d 'only run tests that result has been changed'
|
||||||
complete -c x -n "__fish_x_using_subcommand test" -l rustfix-coverage -d 'enable this to generate a Rustfix coverage file, which is saved in `/<build_base>/rustfix_missing_coverage.txt`'
|
complete -c x -n "__fish_x_using_subcommand test" -l rustfix-coverage -d 'enable this to generate a Rustfix coverage file, which is saved in `/<build_base>/rustfix_missing_coverage.txt`'
|
||||||
|
complete -c x -n "__fish_x_using_subcommand test" -l no-capture -d 'don\'t capture stdout/stderr of tests'
|
||||||
complete -c x -n "__fish_x_using_subcommand test" -s v -l verbose -d 'use verbose output (-vv for very verbose)'
|
complete -c x -n "__fish_x_using_subcommand test" -s v -l verbose -d 'use verbose output (-vv for very verbose)'
|
||||||
complete -c x -n "__fish_x_using_subcommand test" -s i -l incremental -d 'use incremental compilation'
|
complete -c x -n "__fish_x_using_subcommand test" -s i -l incremental -d 'use incremental compilation'
|
||||||
complete -c x -n "__fish_x_using_subcommand test" -l include-default-paths -d 'include default paths in addition to the provided ones'
|
complete -c x -n "__fish_x_using_subcommand test" -l include-default-paths -d 'include default paths in addition to the provided ones'
|
||||||
|
|
|
||||||
|
|
@ -366,6 +366,7 @@ Register-ArgumentCompleter -Native -CommandName 'x' -ScriptBlock {
|
||||||
[CompletionResult]::new('--force-rerun', '--force-rerun', [CompletionResultType]::ParameterName, 'rerun tests even if the inputs are unchanged')
|
[CompletionResult]::new('--force-rerun', '--force-rerun', [CompletionResultType]::ParameterName, 'rerun tests even if the inputs are unchanged')
|
||||||
[CompletionResult]::new('--only-modified', '--only-modified', [CompletionResultType]::ParameterName, 'only run tests that result has been changed')
|
[CompletionResult]::new('--only-modified', '--only-modified', [CompletionResultType]::ParameterName, 'only run tests that result has been changed')
|
||||||
[CompletionResult]::new('--rustfix-coverage', '--rustfix-coverage', [CompletionResultType]::ParameterName, 'enable this to generate a Rustfix coverage file, which is saved in `/<build_base>/rustfix_missing_coverage.txt`')
|
[CompletionResult]::new('--rustfix-coverage', '--rustfix-coverage', [CompletionResultType]::ParameterName, 'enable this to generate a Rustfix coverage file, which is saved in `/<build_base>/rustfix_missing_coverage.txt`')
|
||||||
|
[CompletionResult]::new('--no-capture', '--no-capture', [CompletionResultType]::ParameterName, 'don''t capture stdout/stderr of tests')
|
||||||
[CompletionResult]::new('-v', '-v', [CompletionResultType]::ParameterName, 'use verbose output (-vv for very verbose)')
|
[CompletionResult]::new('-v', '-v', [CompletionResultType]::ParameterName, 'use verbose output (-vv for very verbose)')
|
||||||
[CompletionResult]::new('--verbose', '--verbose', [CompletionResultType]::ParameterName, 'use verbose output (-vv for very verbose)')
|
[CompletionResult]::new('--verbose', '--verbose', [CompletionResultType]::ParameterName, 'use verbose output (-vv for very verbose)')
|
||||||
[CompletionResult]::new('-i', '-i', [CompletionResultType]::ParameterName, 'use incremental compilation')
|
[CompletionResult]::new('-i', '-i', [CompletionResultType]::ParameterName, 'use incremental compilation')
|
||||||
|
|
|
||||||
|
|
@ -319,6 +319,7 @@ complete -c x.py -n "__fish_x.py_using_subcommand test" -l bless -d 'whether to
|
||||||
complete -c x.py -n "__fish_x.py_using_subcommand test" -l force-rerun -d 'rerun tests even if the inputs are unchanged'
|
complete -c x.py -n "__fish_x.py_using_subcommand test" -l force-rerun -d 'rerun tests even if the inputs are unchanged'
|
||||||
complete -c x.py -n "__fish_x.py_using_subcommand test" -l only-modified -d 'only run tests that result has been changed'
|
complete -c x.py -n "__fish_x.py_using_subcommand test" -l only-modified -d 'only run tests that result has been changed'
|
||||||
complete -c x.py -n "__fish_x.py_using_subcommand test" -l rustfix-coverage -d 'enable this to generate a Rustfix coverage file, which is saved in `/<build_base>/rustfix_missing_coverage.txt`'
|
complete -c x.py -n "__fish_x.py_using_subcommand test" -l rustfix-coverage -d 'enable this to generate a Rustfix coverage file, which is saved in `/<build_base>/rustfix_missing_coverage.txt`'
|
||||||
|
complete -c x.py -n "__fish_x.py_using_subcommand test" -l no-capture -d 'don\'t capture stdout/stderr of tests'
|
||||||
complete -c x.py -n "__fish_x.py_using_subcommand test" -s v -l verbose -d 'use verbose output (-vv for very verbose)'
|
complete -c x.py -n "__fish_x.py_using_subcommand test" -s v -l verbose -d 'use verbose output (-vv for very verbose)'
|
||||||
complete -c x.py -n "__fish_x.py_using_subcommand test" -s i -l incremental -d 'use incremental compilation'
|
complete -c x.py -n "__fish_x.py_using_subcommand test" -s i -l incremental -d 'use incremental compilation'
|
||||||
complete -c x.py -n "__fish_x.py_using_subcommand test" -l include-default-paths -d 'include default paths in addition to the provided ones'
|
complete -c x.py -n "__fish_x.py_using_subcommand test" -l include-default-paths -d 'include default paths in addition to the provided ones'
|
||||||
|
|
|
||||||
|
|
@ -366,6 +366,7 @@ Register-ArgumentCompleter -Native -CommandName 'x.py' -ScriptBlock {
|
||||||
[CompletionResult]::new('--force-rerun', '--force-rerun', [CompletionResultType]::ParameterName, 'rerun tests even if the inputs are unchanged')
|
[CompletionResult]::new('--force-rerun', '--force-rerun', [CompletionResultType]::ParameterName, 'rerun tests even if the inputs are unchanged')
|
||||||
[CompletionResult]::new('--only-modified', '--only-modified', [CompletionResultType]::ParameterName, 'only run tests that result has been changed')
|
[CompletionResult]::new('--only-modified', '--only-modified', [CompletionResultType]::ParameterName, 'only run tests that result has been changed')
|
||||||
[CompletionResult]::new('--rustfix-coverage', '--rustfix-coverage', [CompletionResultType]::ParameterName, 'enable this to generate a Rustfix coverage file, which is saved in `/<build_base>/rustfix_missing_coverage.txt`')
|
[CompletionResult]::new('--rustfix-coverage', '--rustfix-coverage', [CompletionResultType]::ParameterName, 'enable this to generate a Rustfix coverage file, which is saved in `/<build_base>/rustfix_missing_coverage.txt`')
|
||||||
|
[CompletionResult]::new('--no-capture', '--no-capture', [CompletionResultType]::ParameterName, 'don''t capture stdout/stderr of tests')
|
||||||
[CompletionResult]::new('-v', '-v', [CompletionResultType]::ParameterName, 'use verbose output (-vv for very verbose)')
|
[CompletionResult]::new('-v', '-v', [CompletionResultType]::ParameterName, 'use verbose output (-vv for very verbose)')
|
||||||
[CompletionResult]::new('--verbose', '--verbose', [CompletionResultType]::ParameterName, 'use verbose output (-vv for very verbose)')
|
[CompletionResult]::new('--verbose', '--verbose', [CompletionResultType]::ParameterName, 'use verbose output (-vv for very verbose)')
|
||||||
[CompletionResult]::new('-i', '-i', [CompletionResultType]::ParameterName, 'use incremental compilation')
|
[CompletionResult]::new('-i', '-i', [CompletionResultType]::ParameterName, 'use incremental compilation')
|
||||||
|
|
|
||||||
|
|
@ -3119,7 +3119,7 @@ _x.py() {
|
||||||
return 0
|
return 0
|
||||||
;;
|
;;
|
||||||
x.py__test)
|
x.py__test)
|
||||||
opts="-v -i -j -h --no-fail-fast --test-args --compiletest-rustc-args --no-doc --doc --bless --extra-checks --force-rerun --only-modified --compare-mode --pass --run --rustfix-coverage --verbose --incremental --config --build-dir --build --host --target --exclude --skip --include-default-paths --rustc-error-format --on-fail --dry-run --dump-bootstrap-shims --stage --keep-stage --keep-stage-std --src --jobs --warnings --error-format --json-output --color --bypass-bootstrap-lock --rust-profile-generate --rust-profile-use --llvm-profile-use --llvm-profile-generate --enable-bolt-settings --skip-stage0-validation --reproducible-artifact --set --help [PATHS]... [ARGS]..."
|
opts="-v -i -j -h --no-fail-fast --test-args --compiletest-rustc-args --no-doc --doc --bless --extra-checks --force-rerun --only-modified --compare-mode --pass --run --rustfix-coverage --no-capture --verbose --incremental --config --build-dir --build --host --target --exclude --skip --include-default-paths --rustc-error-format --on-fail --dry-run --dump-bootstrap-shims --stage --keep-stage --keep-stage-std --src --jobs --warnings --error-format --json-output --color --bypass-bootstrap-lock --rust-profile-generate --rust-profile-use --llvm-profile-use --llvm-profile-generate --enable-bolt-settings --skip-stage0-validation --reproducible-artifact --set --help [PATHS]... [ARGS]..."
|
||||||
if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then
|
if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then
|
||||||
COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") )
|
COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") )
|
||||||
return 0
|
return 0
|
||||||
|
|
|
||||||
|
|
@ -365,6 +365,7 @@ _arguments "${_arguments_options[@]}" : \
|
||||||
'--force-rerun[rerun tests even if the inputs are unchanged]' \
|
'--force-rerun[rerun tests even if the inputs are unchanged]' \
|
||||||
'--only-modified[only run tests that result has been changed]' \
|
'--only-modified[only run tests that result has been changed]' \
|
||||||
'--rustfix-coverage[enable this to generate a Rustfix coverage file, which is saved in \`/<build_base>/rustfix_missing_coverage.txt\`]' \
|
'--rustfix-coverage[enable this to generate a Rustfix coverage file, which is saved in \`/<build_base>/rustfix_missing_coverage.txt\`]' \
|
||||||
|
'--no-capture[don'\''t capture stdout/stderr of tests]' \
|
||||||
'*-v[use verbose output (-vv for very verbose)]' \
|
'*-v[use verbose output (-vv for very verbose)]' \
|
||||||
'*--verbose[use verbose output (-vv for very verbose)]' \
|
'*--verbose[use verbose output (-vv for very verbose)]' \
|
||||||
'-i[use incremental compilation]' \
|
'-i[use incremental compilation]' \
|
||||||
|
|
|
||||||
|
|
@ -3119,7 +3119,7 @@ _x() {
|
||||||
return 0
|
return 0
|
||||||
;;
|
;;
|
||||||
x__test)
|
x__test)
|
||||||
opts="-v -i -j -h --no-fail-fast --test-args --compiletest-rustc-args --no-doc --doc --bless --extra-checks --force-rerun --only-modified --compare-mode --pass --run --rustfix-coverage --verbose --incremental --config --build-dir --build --host --target --exclude --skip --include-default-paths --rustc-error-format --on-fail --dry-run --dump-bootstrap-shims --stage --keep-stage --keep-stage-std --src --jobs --warnings --error-format --json-output --color --bypass-bootstrap-lock --rust-profile-generate --rust-profile-use --llvm-profile-use --llvm-profile-generate --enable-bolt-settings --skip-stage0-validation --reproducible-artifact --set --help [PATHS]... [ARGS]..."
|
opts="-v -i -j -h --no-fail-fast --test-args --compiletest-rustc-args --no-doc --doc --bless --extra-checks --force-rerun --only-modified --compare-mode --pass --run --rustfix-coverage --no-capture --verbose --incremental --config --build-dir --build --host --target --exclude --skip --include-default-paths --rustc-error-format --on-fail --dry-run --dump-bootstrap-shims --stage --keep-stage --keep-stage-std --src --jobs --warnings --error-format --json-output --color --bypass-bootstrap-lock --rust-profile-generate --rust-profile-use --llvm-profile-use --llvm-profile-generate --enable-bolt-settings --skip-stage0-validation --reproducible-artifact --set --help [PATHS]... [ARGS]..."
|
||||||
if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then
|
if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then
|
||||||
COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") )
|
COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") )
|
||||||
return 0
|
return 0
|
||||||
|
|
|
||||||
|
|
@ -365,6 +365,7 @@ _arguments "${_arguments_options[@]}" : \
|
||||||
'--force-rerun[rerun tests even if the inputs are unchanged]' \
|
'--force-rerun[rerun tests even if the inputs are unchanged]' \
|
||||||
'--only-modified[only run tests that result has been changed]' \
|
'--only-modified[only run tests that result has been changed]' \
|
||||||
'--rustfix-coverage[enable this to generate a Rustfix coverage file, which is saved in \`/<build_base>/rustfix_missing_coverage.txt\`]' \
|
'--rustfix-coverage[enable this to generate a Rustfix coverage file, which is saved in \`/<build_base>/rustfix_missing_coverage.txt\`]' \
|
||||||
|
'--no-capture[don'\''t capture stdout/stderr of tests]' \
|
||||||
'*-v[use verbose output (-vv for very verbose)]' \
|
'*-v[use verbose output (-vv for very verbose)]' \
|
||||||
'*--verbose[use verbose output (-vv for very verbose)]' \
|
'*--verbose[use verbose output (-vv for very verbose)]' \
|
||||||
'-i[use incremental compilation]' \
|
'-i[use incremental compilation]' \
|
||||||
|
|
|
||||||
|
|
@ -159,7 +159,9 @@ pub fn parse_config(args: Vec<String>) -> Config {
|
||||||
)
|
)
|
||||||
.optflag("", "force-rerun", "rerun tests even if the inputs are unchanged")
|
.optflag("", "force-rerun", "rerun tests even if the inputs are unchanged")
|
||||||
.optflag("", "only-modified", "only run tests that result been modified")
|
.optflag("", "only-modified", "only run tests that result been modified")
|
||||||
|
// FIXME: Temporarily retained so we can point users to `--no-capture`
|
||||||
.optflag("", "nocapture", "")
|
.optflag("", "nocapture", "")
|
||||||
|
.optflag("", "no-capture", "don't capture stdout/stderr of tests")
|
||||||
.optflag("", "profiler-runtime", "is the profiler runtime enabled for this target")
|
.optflag("", "profiler-runtime", "is the profiler runtime enabled for this target")
|
||||||
.optflag("h", "help", "show this message")
|
.optflag("h", "help", "show this message")
|
||||||
.reqopt("", "channel", "current Rust channel", "CHANNEL")
|
.reqopt("", "channel", "current Rust channel", "CHANNEL")
|
||||||
|
|
@ -288,6 +290,10 @@ pub fn parse_config(args: Vec<String>) -> Config {
|
||||||
);
|
);
|
||||||
})
|
})
|
||||||
});
|
});
|
||||||
|
if matches.opt_present("nocapture") {
|
||||||
|
panic!("`--nocapture` is deprecated; please use `--no-capture`");
|
||||||
|
}
|
||||||
|
|
||||||
Config {
|
Config {
|
||||||
bless: matches.opt_present("bless"),
|
bless: matches.opt_present("bless"),
|
||||||
compile_lib_path: make_absolute(opt_path(matches, "compile-lib-path")),
|
compile_lib_path: make_absolute(opt_path(matches, "compile-lib-path")),
|
||||||
|
|
@ -385,7 +391,7 @@ pub fn parse_config(args: Vec<String>) -> Config {
|
||||||
target_cfgs: OnceLock::new(),
|
target_cfgs: OnceLock::new(),
|
||||||
builtin_cfg_names: OnceLock::new(),
|
builtin_cfg_names: OnceLock::new(),
|
||||||
|
|
||||||
nocapture: matches.opt_present("nocapture"),
|
nocapture: matches.opt_present("no-capture"),
|
||||||
|
|
||||||
git_repository: matches.opt_str("git-repository").unwrap(),
|
git_repository: matches.opt_str("git-repository").unwrap(),
|
||||||
nightly_branch: matches.opt_str("nightly-branch").unwrap(),
|
nightly_branch: matches.opt_str("nightly-branch").unwrap(),
|
||||||
|
|
|
||||||
|
|
@ -213,7 +213,7 @@ fn remove_and_create_dir_all(path: &Path) {
|
||||||
fs::create_dir_all(path).unwrap();
|
fs::create_dir_all(path).unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Copy, Clone)]
|
#[derive(Copy, Clone, Debug)]
|
||||||
struct TestCx<'test> {
|
struct TestCx<'test> {
|
||||||
config: &'test Config,
|
config: &'test Config,
|
||||||
props: &'test TestProps,
|
props: &'test TestProps,
|
||||||
|
|
@ -2318,32 +2318,47 @@ impl<'test> TestCx<'test> {
|
||||||
match output_kind {
|
match output_kind {
|
||||||
TestOutput::Compile => {
|
TestOutput::Compile => {
|
||||||
if !self.props.dont_check_compiler_stdout {
|
if !self.props.dont_check_compiler_stdout {
|
||||||
errors += self.compare_output(
|
if self
|
||||||
|
.compare_output(
|
||||||
|
stdout_kind,
|
||||||
|
&normalized_stdout,
|
||||||
|
&proc_res.stdout,
|
||||||
|
&expected_stdout,
|
||||||
|
)
|
||||||
|
.should_error()
|
||||||
|
{
|
||||||
|
errors += 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if !self.props.dont_check_compiler_stderr {
|
||||||
|
if self
|
||||||
|
.compare_output(stderr_kind, &normalized_stderr, &stderr, &expected_stderr)
|
||||||
|
.should_error()
|
||||||
|
{
|
||||||
|
errors += 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
TestOutput::Run => {
|
||||||
|
if self
|
||||||
|
.compare_output(
|
||||||
stdout_kind,
|
stdout_kind,
|
||||||
&normalized_stdout,
|
&normalized_stdout,
|
||||||
&proc_res.stdout,
|
&proc_res.stdout,
|
||||||
&expected_stdout,
|
&expected_stdout,
|
||||||
);
|
)
|
||||||
|
.should_error()
|
||||||
|
{
|
||||||
|
errors += 1;
|
||||||
}
|
}
|
||||||
if !self.props.dont_check_compiler_stderr {
|
|
||||||
errors += self.compare_output(
|
if self
|
||||||
stderr_kind,
|
.compare_output(stderr_kind, &normalized_stderr, &stderr, &expected_stderr)
|
||||||
&normalized_stderr,
|
.should_error()
|
||||||
&stderr,
|
{
|
||||||
&expected_stderr,
|
errors += 1;
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
TestOutput::Run => {
|
|
||||||
errors += self.compare_output(
|
|
||||||
stdout_kind,
|
|
||||||
&normalized_stdout,
|
|
||||||
&proc_res.stdout,
|
|
||||||
&expected_stdout,
|
|
||||||
);
|
|
||||||
errors +=
|
|
||||||
self.compare_output(stderr_kind, &normalized_stderr, &stderr, &expected_stderr);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
errors
|
errors
|
||||||
}
|
}
|
||||||
|
|
@ -2576,7 +2591,14 @@ impl<'test> TestCx<'test> {
|
||||||
actual: &str,
|
actual: &str,
|
||||||
actual_unnormalized: &str,
|
actual_unnormalized: &str,
|
||||||
expected: &str,
|
expected: &str,
|
||||||
) -> usize {
|
) -> CompareOutcome {
|
||||||
|
let expected_path =
|
||||||
|
expected_output_path(self.testpaths, self.revision, &self.config.compare_mode, stream);
|
||||||
|
|
||||||
|
if self.config.bless && actual.is_empty() && expected_path.exists() {
|
||||||
|
self.delete_file(&expected_path);
|
||||||
|
}
|
||||||
|
|
||||||
let are_different = match (self.force_color_svg(), expected.find('\n'), actual.find('\n')) {
|
let are_different = match (self.force_color_svg(), expected.find('\n'), actual.find('\n')) {
|
||||||
// FIXME: We ignore the first line of SVG files
|
// FIXME: We ignore the first line of SVG files
|
||||||
// because the width parameter is non-deterministic.
|
// because the width parameter is non-deterministic.
|
||||||
|
|
@ -2584,7 +2606,7 @@ impl<'test> TestCx<'test> {
|
||||||
_ => expected != actual,
|
_ => expected != actual,
|
||||||
};
|
};
|
||||||
if !are_different {
|
if !are_different {
|
||||||
return 0;
|
return CompareOutcome::Same;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Wrapper tools set by `runner` might provide extra output on failure,
|
// Wrapper tools set by `runner` might provide extra output on failure,
|
||||||
|
|
@ -2600,7 +2622,7 @@ impl<'test> TestCx<'test> {
|
||||||
used.retain(|line| actual_lines.contains(line));
|
used.retain(|line| actual_lines.contains(line));
|
||||||
// check if `expected` contains a subset of the lines of `actual`
|
// check if `expected` contains a subset of the lines of `actual`
|
||||||
if used.len() == expected_lines.len() && (expected.is_empty() == actual.is_empty()) {
|
if used.len() == expected_lines.len() && (expected.is_empty() == actual.is_empty()) {
|
||||||
return 0;
|
return CompareOutcome::Same;
|
||||||
}
|
}
|
||||||
if expected_lines.is_empty() {
|
if expected_lines.is_empty() {
|
||||||
// if we have no lines to check, force a full overwite
|
// if we have no lines to check, force a full overwite
|
||||||
|
|
@ -2626,9 +2648,6 @@ impl<'test> TestCx<'test> {
|
||||||
}
|
}
|
||||||
println!("Saved the actual {stream} to {actual_path:?}");
|
println!("Saved the actual {stream} to {actual_path:?}");
|
||||||
|
|
||||||
let expected_path =
|
|
||||||
expected_output_path(self.testpaths, self.revision, &self.config.compare_mode, stream);
|
|
||||||
|
|
||||||
if !self.config.bless {
|
if !self.config.bless {
|
||||||
if expected.is_empty() {
|
if expected.is_empty() {
|
||||||
println!("normalized {}:\n{}\n", stream, actual);
|
println!("normalized {}:\n{}\n", stream, actual);
|
||||||
|
|
@ -2651,15 +2670,17 @@ impl<'test> TestCx<'test> {
|
||||||
self.delete_file(&old);
|
self.delete_file(&old);
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Err(err) = fs::write(&expected_path, &actual) {
|
if !actual.is_empty() {
|
||||||
self.fatal(&format!("failed to write {stream} to `{expected_path:?}`: {err}"));
|
if let Err(err) = fs::write(&expected_path, &actual) {
|
||||||
|
self.fatal(&format!("failed to write {stream} to `{expected_path:?}`: {err}"));
|
||||||
|
}
|
||||||
|
println!("Blessing the {stream} of {test_name} in {expected_path:?}");
|
||||||
}
|
}
|
||||||
println!("Blessing the {stream} of {test_name} in {expected_path:?}");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
println!("\nThe actual {0} differed from the expected {0}.", stream);
|
println!("\nThe actual {0} differed from the expected {0}.", stream);
|
||||||
|
|
||||||
if self.config.bless { 0 } else { 1 }
|
if self.config.bless { CompareOutcome::Blessed } else { CompareOutcome::Differed }
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns whether to show the full stderr/stdout.
|
/// Returns whether to show the full stderr/stdout.
|
||||||
|
|
@ -2885,3 +2906,21 @@ enum AuxType {
|
||||||
Dylib,
|
Dylib,
|
||||||
ProcMacro,
|
ProcMacro,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Outcome of comparing a stream to a blessed file,
|
||||||
|
/// e.g. `.stderr` and `.fixed`.
|
||||||
|
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
|
||||||
|
enum CompareOutcome {
|
||||||
|
/// Expected and actual outputs are the same
|
||||||
|
Same,
|
||||||
|
/// Outputs differed but were blessed
|
||||||
|
Blessed,
|
||||||
|
/// Outputs differed and an error should be emitted
|
||||||
|
Differed,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl CompareOutcome {
|
||||||
|
fn should_error(&self) -> bool {
|
||||||
|
matches!(self, CompareOutcome::Differed)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -39,16 +39,16 @@ impl<'test> TestCx<'test> {
|
||||||
let expected_coverage_dump = self.load_expected_output(kind);
|
let expected_coverage_dump = self.load_expected_output(kind);
|
||||||
let actual_coverage_dump = self.normalize_output(&proc_res.stdout, &[]);
|
let actual_coverage_dump = self.normalize_output(&proc_res.stdout, &[]);
|
||||||
|
|
||||||
let coverage_dump_errors = self.compare_output(
|
let coverage_dump_compare_outcome = self.compare_output(
|
||||||
kind,
|
kind,
|
||||||
&actual_coverage_dump,
|
&actual_coverage_dump,
|
||||||
&proc_res.stdout,
|
&proc_res.stdout,
|
||||||
&expected_coverage_dump,
|
&expected_coverage_dump,
|
||||||
);
|
);
|
||||||
|
|
||||||
if coverage_dump_errors > 0 {
|
if coverage_dump_compare_outcome.should_error() {
|
||||||
self.fatal_proc_rec(
|
self.fatal_proc_rec(
|
||||||
&format!("{coverage_dump_errors} errors occurred comparing coverage output."),
|
&format!("an error occurred comparing coverage output."),
|
||||||
&proc_res,
|
&proc_res,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
@ -139,16 +139,16 @@ impl<'test> TestCx<'test> {
|
||||||
self.fatal_proc_rec(&err, &proc_res);
|
self.fatal_proc_rec(&err, &proc_res);
|
||||||
});
|
});
|
||||||
|
|
||||||
let coverage_errors = self.compare_output(
|
let coverage_dump_compare_outcome = self.compare_output(
|
||||||
kind,
|
kind,
|
||||||
&normalized_actual_coverage,
|
&normalized_actual_coverage,
|
||||||
&proc_res.stdout,
|
&proc_res.stdout,
|
||||||
&expected_coverage,
|
&expected_coverage,
|
||||||
);
|
);
|
||||||
|
|
||||||
if coverage_errors > 0 {
|
if coverage_dump_compare_outcome.should_error() {
|
||||||
self.fatal_proc_rec(
|
self.fatal_proc_rec(
|
||||||
&format!("{} errors occurred comparing coverage output.", coverage_errors),
|
&format!("an error occurred comparing coverage output."),
|
||||||
&proc_res,
|
&proc_res,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -100,7 +100,12 @@ impl TestCx<'_> {
|
||||||
)
|
)
|
||||||
});
|
});
|
||||||
|
|
||||||
errors += self.compare_output("fixed", &fixed_code, &fixed_code, &expected_fixed);
|
if self
|
||||||
|
.compare_output("fixed", &fixed_code, &fixed_code, &expected_fixed)
|
||||||
|
.should_error()
|
||||||
|
{
|
||||||
|
errors += 1;
|
||||||
|
}
|
||||||
} else if !expected_fixed.is_empty() {
|
} else if !expected_fixed.is_empty() {
|
||||||
panic!(
|
panic!(
|
||||||
"the `//@ run-rustfix` directive wasn't found but a `*.fixed` \
|
"the `//@ run-rustfix` directive wasn't found but a `*.fixed` \
|
||||||
|
|
|
||||||
137
tests/codegen/intrinsics/carrying_mul_add.rs
Normal file
137
tests/codegen/intrinsics/carrying_mul_add.rs
Normal file
|
|
@ -0,0 +1,137 @@
|
||||||
|
//@ revisions: RAW OPT
|
||||||
|
//@ compile-flags: -C opt-level=1
|
||||||
|
//@[RAW] compile-flags: -C no-prepopulate-passes
|
||||||
|
//@[OPT] min-llvm-version: 19
|
||||||
|
|
||||||
|
#![crate_type = "lib"]
|
||||||
|
#![feature(core_intrinsics)]
|
||||||
|
#![feature(core_intrinsics_fallbacks)]
|
||||||
|
|
||||||
|
// Note that LLVM seems to sometimes permute the order of arguments to mul and add,
|
||||||
|
// so these tests don't check the arguments in the optimized revision.
|
||||||
|
|
||||||
|
use std::intrinsics::{carrying_mul_add, fallback};
|
||||||
|
|
||||||
|
// The fallbacks are emitted even when they're never used, but optimize out.
|
||||||
|
|
||||||
|
// RAW: wide_mul_u128
|
||||||
|
// OPT-NOT: wide_mul_u128
|
||||||
|
|
||||||
|
// CHECK-LABEL: @cma_u8
|
||||||
|
#[no_mangle]
|
||||||
|
pub unsafe fn cma_u8(a: u8, b: u8, c: u8, d: u8) -> (u8, u8) {
|
||||||
|
// CHECK: [[A:%.+]] = zext i8 %a to i16
|
||||||
|
// CHECK: [[B:%.+]] = zext i8 %b to i16
|
||||||
|
// CHECK: [[C:%.+]] = zext i8 %c to i16
|
||||||
|
// CHECK: [[D:%.+]] = zext i8 %d to i16
|
||||||
|
// CHECK: [[AB:%.+]] = mul nuw i16
|
||||||
|
// RAW-SAME: [[A]], [[B]]
|
||||||
|
// CHECK: [[ABC:%.+]] = add nuw i16
|
||||||
|
// RAW-SAME: [[AB]], [[C]]
|
||||||
|
// CHECK: [[ABCD:%.+]] = add nuw i16
|
||||||
|
// RAW-SAME: [[ABC]], [[D]]
|
||||||
|
// CHECK: [[LOW:%.+]] = trunc i16 [[ABCD]] to i8
|
||||||
|
// CHECK: [[HIGHW:%.+]] = lshr i16 [[ABCD]], 8
|
||||||
|
// RAW: [[HIGH:%.+]] = trunc i16 [[HIGHW]] to i8
|
||||||
|
// OPT: [[HIGH:%.+]] = trunc nuw i16 [[HIGHW]] to i8
|
||||||
|
// CHECK: [[PAIR0:%.+]] = insertvalue { i8, i8 } poison, i8 [[LOW]], 0
|
||||||
|
// CHECK: [[PAIR1:%.+]] = insertvalue { i8, i8 } [[PAIR0]], i8 [[HIGH]], 1
|
||||||
|
// OPT: ret { i8, i8 } [[PAIR1]]
|
||||||
|
carrying_mul_add(a, b, c, d)
|
||||||
|
}
|
||||||
|
|
||||||
|
// CHECK-LABEL: @cma_u32
|
||||||
|
#[no_mangle]
|
||||||
|
pub unsafe fn cma_u32(a: u32, b: u32, c: u32, d: u32) -> (u32, u32) {
|
||||||
|
// CHECK: [[A:%.+]] = zext i32 %a to i64
|
||||||
|
// CHECK: [[B:%.+]] = zext i32 %b to i64
|
||||||
|
// CHECK: [[C:%.+]] = zext i32 %c to i64
|
||||||
|
// CHECK: [[D:%.+]] = zext i32 %d to i64
|
||||||
|
// CHECK: [[AB:%.+]] = mul nuw i64
|
||||||
|
// RAW-SAME: [[A]], [[B]]
|
||||||
|
// CHECK: [[ABC:%.+]] = add nuw i64
|
||||||
|
// RAW-SAME: [[AB]], [[C]]
|
||||||
|
// CHECK: [[ABCD:%.+]] = add nuw i64
|
||||||
|
// RAW-SAME: [[ABC]], [[D]]
|
||||||
|
// CHECK: [[LOW:%.+]] = trunc i64 [[ABCD]] to i32
|
||||||
|
// CHECK: [[HIGHW:%.+]] = lshr i64 [[ABCD]], 32
|
||||||
|
// RAW: [[HIGH:%.+]] = trunc i64 [[HIGHW]] to i32
|
||||||
|
// OPT: [[HIGH:%.+]] = trunc nuw i64 [[HIGHW]] to i32
|
||||||
|
// CHECK: [[PAIR0:%.+]] = insertvalue { i32, i32 } poison, i32 [[LOW]], 0
|
||||||
|
// CHECK: [[PAIR1:%.+]] = insertvalue { i32, i32 } [[PAIR0]], i32 [[HIGH]], 1
|
||||||
|
// OPT: ret { i32, i32 } [[PAIR1]]
|
||||||
|
carrying_mul_add(a, b, c, d)
|
||||||
|
}
|
||||||
|
|
||||||
|
// CHECK-LABEL: @cma_u128
|
||||||
|
// CHECK-SAME: sret{{.+}}dereferenceable(32){{.+}}%_0,{{.+}}%a,{{.+}}%b,{{.+}}%c,{{.+}}%d
|
||||||
|
#[no_mangle]
|
||||||
|
pub unsafe fn cma_u128(a: u128, b: u128, c: u128, d: u128) -> (u128, u128) {
|
||||||
|
// CHECK: [[A:%.+]] = zext i128 %a to i256
|
||||||
|
// CHECK: [[B:%.+]] = zext i128 %b to i256
|
||||||
|
// CHECK: [[C:%.+]] = zext i128 %c to i256
|
||||||
|
// CHECK: [[D:%.+]] = zext i128 %d to i256
|
||||||
|
// CHECK: [[AB:%.+]] = mul nuw i256
|
||||||
|
// RAW-SAME: [[A]], [[B]]
|
||||||
|
// CHECK: [[ABC:%.+]] = add nuw i256
|
||||||
|
// RAW-SAME: [[AB]], [[C]]
|
||||||
|
// CHECK: [[ABCD:%.+]] = add nuw i256
|
||||||
|
// RAW-SAME: [[ABC]], [[D]]
|
||||||
|
// CHECK: [[LOW:%.+]] = trunc i256 [[ABCD]] to i128
|
||||||
|
// CHECK: [[HIGHW:%.+]] = lshr i256 [[ABCD]], 128
|
||||||
|
// RAW: [[HIGH:%.+]] = trunc i256 [[HIGHW]] to i128
|
||||||
|
// OPT: [[HIGH:%.+]] = trunc nuw i256 [[HIGHW]] to i128
|
||||||
|
// RAW: [[PAIR0:%.+]] = insertvalue { i128, i128 } poison, i128 [[LOW]], 0
|
||||||
|
// RAW: [[PAIR1:%.+]] = insertvalue { i128, i128 } [[PAIR0]], i128 [[HIGH]], 1
|
||||||
|
// OPT: store i128 [[LOW]], ptr %_0
|
||||||
|
// OPT: [[P1:%.+]] = getelementptr inbounds i8, ptr %_0, {{i32|i64}} 16
|
||||||
|
// OPT: store i128 [[HIGH]], ptr [[P1]]
|
||||||
|
// CHECK: ret void
|
||||||
|
carrying_mul_add(a, b, c, d)
|
||||||
|
}
|
||||||
|
|
||||||
|
// CHECK-LABEL: @cma_i128
|
||||||
|
// CHECK-SAME: sret{{.+}}dereferenceable(32){{.+}}%_0,{{.+}}%a,{{.+}}%b,{{.+}}%c,{{.+}}%d
|
||||||
|
#[no_mangle]
|
||||||
|
pub unsafe fn cma_i128(a: i128, b: i128, c: i128, d: i128) -> (u128, i128) {
|
||||||
|
// CHECK: [[A:%.+]] = sext i128 %a to i256
|
||||||
|
// CHECK: [[B:%.+]] = sext i128 %b to i256
|
||||||
|
// CHECK: [[C:%.+]] = sext i128 %c to i256
|
||||||
|
// CHECK: [[D:%.+]] = sext i128 %d to i256
|
||||||
|
// CHECK: [[AB:%.+]] = mul nsw i256
|
||||||
|
// RAW-SAME: [[A]], [[B]]
|
||||||
|
// CHECK: [[ABC:%.+]] = add nsw i256
|
||||||
|
// RAW-SAME: [[AB]], [[C]]
|
||||||
|
// CHECK: [[ABCD:%.+]] = add nsw i256
|
||||||
|
// RAW-SAME: [[ABC]], [[D]]
|
||||||
|
// CHECK: [[LOW:%.+]] = trunc i256 [[ABCD]] to i128
|
||||||
|
// CHECK: [[HIGHW:%.+]] = lshr i256 [[ABCD]], 128
|
||||||
|
// RAW: [[HIGH:%.+]] = trunc i256 [[HIGHW]] to i128
|
||||||
|
// OPT: [[HIGH:%.+]] = trunc nuw i256 [[HIGHW]] to i128
|
||||||
|
// RAW: [[PAIR0:%.+]] = insertvalue { i128, i128 } poison, i128 [[LOW]], 0
|
||||||
|
// RAW: [[PAIR1:%.+]] = insertvalue { i128, i128 } [[PAIR0]], i128 [[HIGH]], 1
|
||||||
|
// OPT: store i128 [[LOW]], ptr %_0
|
||||||
|
// OPT: [[P1:%.+]] = getelementptr inbounds i8, ptr %_0, {{i32|i64}} 16
|
||||||
|
// OPT: store i128 [[HIGH]], ptr [[P1]]
|
||||||
|
// CHECK: ret void
|
||||||
|
carrying_mul_add(a, b, c, d)
|
||||||
|
}
|
||||||
|
|
||||||
|
// CHECK-LABEL: @fallback_cma_u32
|
||||||
|
#[no_mangle]
|
||||||
|
pub unsafe fn fallback_cma_u32(a: u32, b: u32, c: u32, d: u32) -> (u32, u32) {
|
||||||
|
// OPT-DAG: [[A:%.+]] = zext i32 %a to i64
|
||||||
|
// OPT-DAG: [[B:%.+]] = zext i32 %b to i64
|
||||||
|
// OPT-DAG: [[AB:%.+]] = mul nuw i64
|
||||||
|
// OPT-DAG: [[C:%.+]] = zext i32 %c to i64
|
||||||
|
// OPT-DAG: [[ABC:%.+]] = add nuw i64{{.+}}[[C]]
|
||||||
|
// OPT-DAG: [[D:%.+]] = zext i32 %d to i64
|
||||||
|
// OPT-DAG: [[ABCD:%.+]] = add nuw i64{{.+}}[[D]]
|
||||||
|
// OPT-DAG: [[LOW:%.+]] = trunc i64 [[ABCD]] to i32
|
||||||
|
// OPT-DAG: [[HIGHW:%.+]] = lshr i64 [[ABCD]], 32
|
||||||
|
// OPT-DAG: [[HIGH:%.+]] = trunc nuw i64 [[HIGHW]] to i32
|
||||||
|
// OPT-DAG: [[PAIR0:%.+]] = insertvalue { i32, i32 } poison, i32 [[LOW]], 0
|
||||||
|
// OPT-DAG: [[PAIR1:%.+]] = insertvalue { i32, i32 } [[PAIR0]], i32 [[HIGH]], 1
|
||||||
|
// OPT-DAG: ret { i32, i32 } [[PAIR1]]
|
||||||
|
fallback::CarryingMulAdd::carrying_mul_add(a, b, c, d)
|
||||||
|
}
|
||||||
14
tests/ui/consts/error-is-freeze.rs
Normal file
14
tests/ui/consts/error-is-freeze.rs
Normal file
|
|
@ -0,0 +1,14 @@
|
||||||
|
// Make sure we treat the error type as freeze to suppress useless errors.
|
||||||
|
|
||||||
|
struct MyStruct {
|
||||||
|
foo: Option<UndefinedType>,
|
||||||
|
//~^ ERROR cannot find type `UndefinedType` in this scope
|
||||||
|
}
|
||||||
|
impl MyStruct {
|
||||||
|
pub const EMPTY_REF: &'static Self = &Self::EMPTY;
|
||||||
|
pub const EMPTY: Self = Self {
|
||||||
|
foo: None,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {}
|
||||||
14
tests/ui/consts/error-is-freeze.stderr
Normal file
14
tests/ui/consts/error-is-freeze.stderr
Normal file
|
|
@ -0,0 +1,14 @@
|
||||||
|
error[E0412]: cannot find type `UndefinedType` in this scope
|
||||||
|
--> $DIR/error-is-freeze.rs:4:17
|
||||||
|
|
|
||||||
|
LL | foo: Option<UndefinedType>,
|
||||||
|
| ^^^^^^^^^^^^^ not found in this scope
|
||||||
|
|
|
||||||
|
help: you might be missing a type parameter
|
||||||
|
|
|
||||||
|
LL | struct MyStruct<UndefinedType> {
|
||||||
|
| +++++++++++++++
|
||||||
|
|
||||||
|
error: aborting due to 1 previous error
|
||||||
|
|
||||||
|
For more information about this error, try `rustc --explain E0412`.
|
||||||
|
|
@ -1,9 +1,9 @@
|
||||||
//@ known-bug: #131050
|
|
||||||
//@ compile-flags: --edition=2021
|
//@ compile-flags: --edition=2021
|
||||||
|
|
||||||
use std::future::Future;
|
use std::future::Future;
|
||||||
|
|
||||||
fn invalid_future() -> impl Future {}
|
fn invalid_future() -> impl Future {}
|
||||||
|
//~^ ERROR `()` is not a future
|
||||||
|
|
||||||
fn create_complex_future() -> impl Future<Output = impl ReturnsSend> {
|
fn create_complex_future() -> impl Future<Output = impl ReturnsSend> {
|
||||||
async { &|| async { invalid_future().await } }
|
async { &|| async { invalid_future().await } }
|
||||||
|
|
@ -21,3 +21,5 @@ where
|
||||||
R: Send,
|
R: Send,
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn main() {}
|
||||||
11
tests/ui/impl-trait/auto-trait-contains-err.stderr
Normal file
11
tests/ui/impl-trait/auto-trait-contains-err.stderr
Normal file
|
|
@ -0,0 +1,11 @@
|
||||||
|
error[E0277]: `()` is not a future
|
||||||
|
--> $DIR/auto-trait-contains-err.rs:5:24
|
||||||
|
|
|
||||||
|
LL | fn invalid_future() -> impl Future {}
|
||||||
|
| ^^^^^^^^^^^ `()` is not a future
|
||||||
|
|
|
||||||
|
= help: the trait `Future` is not implemented for `()`
|
||||||
|
|
||||||
|
error: aborting due to 1 previous error
|
||||||
|
|
||||||
|
For more information about this error, try `rustc --explain E0277`.
|
||||||
|
|
@ -997,6 +997,7 @@ users_on_vacation = [
|
||||||
"jyn514",
|
"jyn514",
|
||||||
"celinval",
|
"celinval",
|
||||||
"nnethercote",
|
"nnethercote",
|
||||||
|
"spastorino",
|
||||||
"workingjubilee",
|
"workingjubilee",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
@ -1046,6 +1047,7 @@ bootstrap = [
|
||||||
"@onur-ozkan",
|
"@onur-ozkan",
|
||||||
"@kobzol",
|
"@kobzol",
|
||||||
"@jieyouxu",
|
"@jieyouxu",
|
||||||
|
"@clubby789",
|
||||||
]
|
]
|
||||||
infra-ci = [
|
infra-ci = [
|
||||||
"@Mark-Simulacrum",
|
"@Mark-Simulacrum",
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue