Auto merge of #144219 - GuillaumeGomez:rollup-ha29sql, r=GuillaumeGomez
Rollup of 9 pull requests Successful merges: - rust-lang/rust#143282 (Add `uX::strict_sub_signed`) - rust-lang/rust#143423 (address clippy formatting nits) - rust-lang/rust#143720 (Allow `Rvalue::Repeat` to return true in `rvalue_creates_operand` too) - rust-lang/rust#144011 (bootstrap: Don't trigger an unnecessary LLVM build from check builds) - rust-lang/rust#144112 (bootstrap: Ignore `rust.debuginfo-level-tests` for codegen tests) - rust-lang/rust#144125 (Add new `ignore-backends` and `needs-backends` tests annotations) - rust-lang/rust#144143 (Fix `-Ctarget-feature`s getting ignored after `crt-static`) - rust-lang/rust#144150 (tests: assembly: cstring-merging: Disable GlobalMerge pass) - rust-lang/rust#144190 (Give a message with a span on MIR validation error) r? `@ghost` `@rustbot` modify labels: rollup
This commit is contained in:
commit
0864097cd3
31 changed files with 350 additions and 88 deletions
|
|
@ -630,7 +630,17 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
|
|||
OperandRef { val: OperandValue::Immediate(static_), layout }
|
||||
}
|
||||
mir::Rvalue::Use(ref operand) => self.codegen_operand(bx, operand),
|
||||
mir::Rvalue::Repeat(..) => bug!("{rvalue:?} in codegen_rvalue_operand"),
|
||||
mir::Rvalue::Repeat(ref elem, len_const) => {
|
||||
// All arrays have `BackendRepr::Memory`, so only the ZST cases
|
||||
// end up here. Anything else forces the destination local to be
|
||||
// `Memory`, and thus ends up handled in `codegen_rvalue` instead.
|
||||
let operand = self.codegen_operand(bx, elem);
|
||||
let array_ty = Ty::new_array_with_const_len(bx.tcx(), operand.layout.ty, len_const);
|
||||
let array_ty = self.monomorphize(array_ty);
|
||||
let array_layout = bx.layout_of(array_ty);
|
||||
assert!(array_layout.is_zst());
|
||||
OperandRef { val: OperandValue::ZeroSized, layout: array_layout }
|
||||
}
|
||||
mir::Rvalue::Aggregate(ref kind, ref fields) => {
|
||||
let (variant_index, active_field_index) = match **kind {
|
||||
mir::AggregateKind::Adt(_, variant_index, _, _, active_field_index) => {
|
||||
|
|
@ -1000,12 +1010,10 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
|
|||
mir::Rvalue::NullaryOp(..) |
|
||||
mir::Rvalue::ThreadLocalRef(_) |
|
||||
mir::Rvalue::Use(..) |
|
||||
mir::Rvalue::Repeat(..) | // (*)
|
||||
mir::Rvalue::Aggregate(..) | // (*)
|
||||
mir::Rvalue::WrapUnsafeBinder(..) => // (*)
|
||||
true,
|
||||
// Arrays are always aggregates, so it's not worth checking anything here.
|
||||
// (If it's really `[(); N]` or `[T; 0]` and we use the place path, fine.)
|
||||
mir::Rvalue::Repeat(..) => false,
|
||||
}
|
||||
|
||||
// (*) this is only true if the type is suitable
|
||||
|
|
|
|||
|
|
@ -149,14 +149,14 @@ fn parse_rust_feature_flag<'a>(
|
|||
if let Some(base_feature) = feature.strip_prefix('+') {
|
||||
// Skip features that are not target features, but rustc features.
|
||||
if RUSTC_SPECIFIC_FEATURES.contains(&base_feature) {
|
||||
return;
|
||||
continue;
|
||||
}
|
||||
|
||||
callback(base_feature, sess.target.implied_target_features(base_feature), true)
|
||||
} else if let Some(base_feature) = feature.strip_prefix('-') {
|
||||
// Skip features that are not target features, but rustc features.
|
||||
if RUSTC_SPECIFIC_FEATURES.contains(&base_feature) {
|
||||
return;
|
||||
continue;
|
||||
}
|
||||
|
||||
// If `f1` implies `f2`, then `!f2` implies `!f1` -- this is standard logical
|
||||
|
|
|
|||
|
|
@ -119,14 +119,16 @@ impl<'a, 'tcx> CfgChecker<'a, 'tcx> {
|
|||
#[track_caller]
|
||||
fn fail(&self, location: Location, msg: impl AsRef<str>) {
|
||||
// We might see broken MIR when other errors have already occurred.
|
||||
assert!(
|
||||
self.tcx.dcx().has_errors().is_some(),
|
||||
"broken MIR in {:?} ({}) at {:?}:\n{}",
|
||||
self.body.source.instance,
|
||||
self.when,
|
||||
location,
|
||||
msg.as_ref(),
|
||||
);
|
||||
if self.tcx.dcx().has_errors().is_none() {
|
||||
span_bug!(
|
||||
self.body.source_info(location).span,
|
||||
"broken MIR in {:?} ({}) at {:?}:\n{}",
|
||||
self.body.source.instance,
|
||||
self.when,
|
||||
location,
|
||||
msg.as_ref(),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
fn check_edge(&mut self, location: Location, bb: BasicBlock, edge_kind: EdgeKind) {
|
||||
|
|
|
|||
|
|
@ -28,15 +28,15 @@ pub trait AsyncIterator {
|
|||
/// async iterator state:
|
||||
///
|
||||
/// - `Poll::Pending` means that this async iterator's next value is not ready
|
||||
/// yet. Implementations will ensure that the current task will be notified
|
||||
/// when the next value may be ready.
|
||||
/// yet. Implementations will ensure that the current task will be notified
|
||||
/// when the next value may be ready.
|
||||
///
|
||||
/// - `Poll::Ready(Some(val))` means that the async iterator has successfully
|
||||
/// produced a value, `val`, and may produce further values on subsequent
|
||||
/// `poll_next` calls.
|
||||
/// produced a value, `val`, and may produce further values on subsequent
|
||||
/// `poll_next` calls.
|
||||
///
|
||||
/// - `Poll::Ready(None)` means that the async iterator has terminated, and
|
||||
/// `poll_next` should not be invoked again.
|
||||
/// `poll_next` should not be invoked again.
|
||||
///
|
||||
/// # Panics
|
||||
///
|
||||
|
|
|
|||
|
|
@ -1482,13 +1482,14 @@ pub trait PartialOrd<Rhs: PointeeSized = Self>: PartialEq<Rhs> + PointeeSized {
|
|||
}
|
||||
}
|
||||
|
||||
fn default_chaining_impl<T: PointeeSized, U: PointeeSized>(
|
||||
fn default_chaining_impl<T, U>(
|
||||
lhs: &T,
|
||||
rhs: &U,
|
||||
p: impl FnOnce(Ordering) -> bool,
|
||||
) -> ControlFlow<bool>
|
||||
where
|
||||
T: PartialOrd<U>,
|
||||
T: PartialOrd<U> + PointeeSized,
|
||||
U: PointeeSized,
|
||||
{
|
||||
// It's important that this only call `partial_cmp` once, not call `eq` then
|
||||
// one of the relational operators. We don't want to `bcmp`-then-`memcp` a
|
||||
|
|
|
|||
|
|
@ -854,7 +854,6 @@ impl Display for Arguments<'_> {
|
|||
/// }";
|
||||
/// assert_eq!(format!("The origin is: {origin:#?}"), expected);
|
||||
/// ```
|
||||
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
#[rustc_on_unimplemented(
|
||||
on(
|
||||
|
|
|
|||
|
|
@ -436,7 +436,6 @@ pub trait Extend<A> {
|
|||
/// **For implementors:** For a collection to unsafely rely on this method's safety precondition (that is,
|
||||
/// invoke UB if they are violated), it must implement `extend_reserve` correctly. In other words,
|
||||
/// callers may assume that if they `extend_reserve`ed enough space they can call this method.
|
||||
|
||||
// This method is for internal usage only. It is only on the trait because of specialization's limitations.
|
||||
#[unstable(feature = "extend_one_unchecked", issue = "none")]
|
||||
#[doc(hidden)]
|
||||
|
|
|
|||
|
|
@ -3414,10 +3414,10 @@ pub trait Iterator {
|
|||
/// ```
|
||||
#[stable(feature = "iter_copied", since = "1.36.0")]
|
||||
#[rustc_diagnostic_item = "iter_copied"]
|
||||
fn copied<'a, T: 'a>(self) -> Copied<Self>
|
||||
fn copied<'a, T>(self) -> Copied<Self>
|
||||
where
|
||||
T: Copy + 'a,
|
||||
Self: Sized + Iterator<Item = &'a T>,
|
||||
T: Copy,
|
||||
{
|
||||
Copied::new(self)
|
||||
}
|
||||
|
|
@ -3462,10 +3462,10 @@ pub trait Iterator {
|
|||
/// ```
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
#[rustc_diagnostic_item = "iter_cloned"]
|
||||
fn cloned<'a, T: 'a>(self) -> Cloned<Self>
|
||||
fn cloned<'a, T>(self) -> Cloned<Self>
|
||||
where
|
||||
T: Clone + 'a,
|
||||
Self: Sized + Iterator<Item = &'a T>,
|
||||
T: Clone,
|
||||
{
|
||||
Cloned::new(self)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -39,9 +39,9 @@
|
|||
//! return. You should mark your implementation using `#[panic_handler]`.
|
||||
//!
|
||||
//! * `rust_eh_personality` - is used by the failure mechanisms of the
|
||||
//! compiler. This is often mapped to GCC's personality function, but crates
|
||||
//! which do not trigger a panic can be assured that this function is never
|
||||
//! called. The `lang` attribute is called `eh_personality`.
|
||||
//! compiler. This is often mapped to GCC's personality function, but crates
|
||||
//! which do not trigger a panic can be assured that this function is never
|
||||
//! called. The `lang` attribute is called `eh_personality`.
|
||||
|
||||
#![stable(feature = "core", since = "1.6.0")]
|
||||
#![doc(
|
||||
|
|
|
|||
|
|
@ -36,7 +36,7 @@ pub use crate::intrinsics::transmute;
|
|||
/// * If you want to leak memory, see [`Box::leak`].
|
||||
/// * If you want to obtain a raw pointer to the memory, see [`Box::into_raw`].
|
||||
/// * If you want to dispose of a value properly, running its destructor, see
|
||||
/// [`mem::drop`].
|
||||
/// [`mem::drop`].
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
|
|
|
|||
|
|
@ -787,7 +787,6 @@ impl Ipv4Addr {
|
|||
/// [IANA IPv4 Special-Purpose Address Registry]: https://www.iana.org/assignments/iana-ipv4-special-registry/iana-ipv4-special-registry.xhtml
|
||||
/// [unspecified address]: Ipv4Addr::UNSPECIFIED
|
||||
/// [broadcast address]: Ipv4Addr::BROADCAST
|
||||
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
/// These functions compute the integer logarithm of their type, assuming
|
||||
/// that someone has already checked that the value is strictly positive.
|
||||
//! These functions compute the integer logarithm of their type, assuming
|
||||
//! that someone has already checked that the value is strictly positive.
|
||||
|
||||
// 0 < val <= u8::MAX
|
||||
#[inline]
|
||||
|
|
|
|||
|
|
@ -556,7 +556,7 @@ macro_rules! uint_impl {
|
|||
pub const fn strict_add(self, rhs: Self) -> Self {
|
||||
let (a, b) = self.overflowing_add(rhs);
|
||||
if b { overflow_panic::add() } else { a }
|
||||
}
|
||||
}
|
||||
|
||||
/// Unchecked integer addition. Computes `self + rhs`, assuming overflow
|
||||
/// cannot occur.
|
||||
|
|
@ -653,7 +653,7 @@ macro_rules! uint_impl {
|
|||
pub const fn strict_add_signed(self, rhs: $SignedT) -> Self {
|
||||
let (a, b) = self.overflowing_add_signed(rhs);
|
||||
if b { overflow_panic::add() } else { a }
|
||||
}
|
||||
}
|
||||
|
||||
/// Checked integer subtraction. Computes `self - rhs`, returning
|
||||
/// `None` if overflow occurred.
|
||||
|
|
@ -713,7 +713,7 @@ macro_rules! uint_impl {
|
|||
pub const fn strict_sub(self, rhs: Self) -> Self {
|
||||
let (a, b) = self.overflowing_sub(rhs);
|
||||
if b { overflow_panic::sub() } else { a }
|
||||
}
|
||||
}
|
||||
|
||||
/// Unchecked integer subtraction. Computes `self - rhs`, assuming overflow
|
||||
/// cannot occur.
|
||||
|
|
@ -805,6 +805,43 @@ macro_rules! uint_impl {
|
|||
}
|
||||
}
|
||||
|
||||
/// Strict subtraction with a signed integer. Computes `self - rhs`,
|
||||
/// panicking if overflow occurred.
|
||||
///
|
||||
/// # Panics
|
||||
///
|
||||
/// ## Overflow behavior
|
||||
///
|
||||
/// This function will always panic on overflow, regardless of whether overflow checks are enabled.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// #![feature(strict_overflow_ops)]
|
||||
#[doc = concat!("assert_eq!(3", stringify!($SelfT), ".strict_sub_signed(2), 1);")]
|
||||
/// ```
|
||||
///
|
||||
/// The following panic because of overflow:
|
||||
///
|
||||
/// ```should_panic
|
||||
/// #![feature(strict_overflow_ops)]
|
||||
#[doc = concat!("let _ = 1", stringify!($SelfT), ".strict_sub_signed(2);")]
|
||||
/// ```
|
||||
///
|
||||
/// ```should_panic
|
||||
/// #![feature(strict_overflow_ops)]
|
||||
#[doc = concat!("let _ = (", stringify!($SelfT), "::MAX).strict_sub_signed(-1);")]
|
||||
/// ```
|
||||
#[unstable(feature = "strict_overflow_ops", issue = "118260")]
|
||||
#[must_use = "this returns the result of the operation, \
|
||||
without modifying the original"]
|
||||
#[inline]
|
||||
#[track_caller]
|
||||
pub const fn strict_sub_signed(self, rhs: $SignedT) -> Self {
|
||||
let (a, b) = self.overflowing_sub_signed(rhs);
|
||||
if b { overflow_panic::sub() } else { a }
|
||||
}
|
||||
|
||||
#[doc = concat!(
|
||||
"Checked integer subtraction. Computes `self - rhs` and checks if the result fits into an [`",
|
||||
stringify!($SignedT), "`], returning `None` if overflow occurred."
|
||||
|
|
@ -913,7 +950,7 @@ macro_rules! uint_impl {
|
|||
pub const fn strict_mul(self, rhs: Self) -> Self {
|
||||
let (a, b) = self.overflowing_mul(rhs);
|
||||
if b { overflow_panic::mul() } else { a }
|
||||
}
|
||||
}
|
||||
|
||||
/// Unchecked integer multiplication. Computes `self * rhs`, assuming overflow
|
||||
/// cannot occur.
|
||||
|
|
|
|||
|
|
@ -1363,7 +1363,6 @@ mod prim_f16 {}
|
|||
/// x = a + b + c + d; // As written
|
||||
/// x = (a + c) + (b + d); // Reordered to shorten critical path and enable vectorization
|
||||
/// ```
|
||||
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
mod prim_f32 {}
|
||||
|
||||
|
|
|
|||
|
|
@ -10,24 +10,24 @@ When calling this method, you have to ensure that *either* the pointer is null *
|
|||
all of the following is true:
|
||||
|
||||
* The pointer must be [valid] for reads for `ptr.len() * size_of::<T>()` many bytes,
|
||||
and it must be properly aligned. This means in particular:
|
||||
and it must be properly aligned. This means in particular:
|
||||
|
||||
* The entire memory range of this slice must be contained within a single [allocation]!
|
||||
Slices can never span across multiple allocations.
|
||||
Slices can never span across multiple allocations.
|
||||
|
||||
* The pointer must be aligned even for zero-length slices. One
|
||||
reason for this is that enum layout optimizations may rely on references
|
||||
(including slices of any length) being aligned and non-null to distinguish
|
||||
them from other data. You can obtain a pointer that is usable as `data`
|
||||
for zero-length slices using [`NonNull::dangling()`].
|
||||
reason for this is that enum layout optimizations may rely on references
|
||||
(including slices of any length) being aligned and non-null to distinguish
|
||||
them from other data. You can obtain a pointer that is usable as `data`
|
||||
for zero-length slices using [`NonNull::dangling()`].
|
||||
|
||||
* The total size `ptr.len() * size_of::<T>()` of the slice must be no larger than `isize::MAX`.
|
||||
See the safety documentation of [`pointer::offset`].
|
||||
See the safety documentation of [`pointer::offset`].
|
||||
|
||||
* You must enforce Rust's aliasing rules, since the returned lifetime `'a` is
|
||||
arbitrarily chosen and does not necessarily reflect the actual lifetime of the data.
|
||||
In particular, while this reference exists, the memory the pointer points to must
|
||||
not get mutated (except inside `UnsafeCell`).
|
||||
arbitrarily chosen and does not necessarily reflect the actual lifetime of the data.
|
||||
In particular, while this reference exists, the memory the pointer points to must
|
||||
not get mutated (except inside `UnsafeCell`).
|
||||
|
||||
This applies even if the result of this method is unused!
|
||||
|
||||
|
|
|
|||
|
|
@ -2651,7 +2651,6 @@ impl str {
|
|||
/// you're trying to parse into.
|
||||
///
|
||||
/// `parse` can parse into any type that implements the [`FromStr`] trait.
|
||||
|
||||
///
|
||||
/// # Errors
|
||||
///
|
||||
|
|
|
|||
|
|
@ -355,7 +355,7 @@ impl Step for CodegenBackend {
|
|||
cargo
|
||||
.arg("--manifest-path")
|
||||
.arg(builder.src.join(format!("compiler/rustc_codegen_{backend}/Cargo.toml")));
|
||||
rustc_cargo_env(builder, &mut cargo, target, build_compiler.stage);
|
||||
rustc_cargo_env(builder, &mut cargo, target);
|
||||
|
||||
let _guard = builder.msg_check(format!("rustc_codegen_{backend}"), target, None);
|
||||
|
||||
|
|
|
|||
|
|
@ -1316,15 +1316,10 @@ pub fn rustc_cargo(
|
|||
cargo.env("RUSTC_WRAPPER", ccache);
|
||||
}
|
||||
|
||||
rustc_cargo_env(builder, cargo, target, build_compiler.stage);
|
||||
rustc_cargo_env(builder, cargo, target);
|
||||
}
|
||||
|
||||
pub fn rustc_cargo_env(
|
||||
builder: &Builder<'_>,
|
||||
cargo: &mut Cargo,
|
||||
target: TargetSelection,
|
||||
build_stage: u32,
|
||||
) {
|
||||
pub fn rustc_cargo_env(builder: &Builder<'_>, cargo: &mut Cargo, target: TargetSelection) {
|
||||
// Set some configuration variables picked up by build scripts and
|
||||
// the compiler alike
|
||||
cargo
|
||||
|
|
@ -1379,18 +1374,24 @@ pub fn rustc_cargo_env(
|
|||
cargo.rustflag("--cfg=llvm_enzyme");
|
||||
}
|
||||
|
||||
// Note that this is disabled if LLVM itself is disabled or we're in a check
|
||||
// build. If we are in a check build we still go ahead here presuming we've
|
||||
// detected that LLVM is already built and good to go which helps prevent
|
||||
// busting caches (e.g. like #71152).
|
||||
// These conditionals represent a tension between three forces:
|
||||
// - For non-check builds, we need to define some LLVM-related environment
|
||||
// variables, requiring LLVM to have been built.
|
||||
// - For check builds, we want to avoid building LLVM if possible.
|
||||
// - Check builds and non-check builds should have the same environment if
|
||||
// possible, to avoid unnecessary rebuilds due to cache-busting.
|
||||
//
|
||||
// Therefore we try to avoid building LLVM for check builds, but only if
|
||||
// building LLVM would be expensive. If "building" LLVM is cheap
|
||||
// (i.e. it's already built or is downloadable), we prefer to maintain a
|
||||
// consistent environment between check and non-check builds.
|
||||
if builder.config.llvm_enabled(target) {
|
||||
let building_is_expensive =
|
||||
let building_llvm_is_expensive =
|
||||
crate::core::build_steps::llvm::prebuilt_llvm_config(builder, target, false)
|
||||
.should_build();
|
||||
// `top_stage == stage` might be false for `check --stage 1`, if we are building the stage 1 compiler
|
||||
let can_skip_build = builder.kind == Kind::Check && builder.top_stage == build_stage;
|
||||
let should_skip_build = building_is_expensive && can_skip_build;
|
||||
if !should_skip_build {
|
||||
|
||||
let skip_llvm = (builder.kind == Kind::Check) && building_llvm_is_expensive;
|
||||
if !skip_llvm {
|
||||
rustc_llvm_env(builder, cargo, target)
|
||||
}
|
||||
}
|
||||
|
|
@ -1407,6 +1408,9 @@ pub fn rustc_cargo_env(
|
|||
|
||||
/// Pass down configuration from the LLVM build into the build of
|
||||
/// rustc_llvm and rustc_codegen_llvm.
|
||||
///
|
||||
/// Note that this has the side-effect of _building LLVM_, which is sometimes
|
||||
/// unwanted (e.g. for check builds).
|
||||
fn rustc_llvm_env(builder: &Builder<'_>, cargo: &mut Cargo, target: TargetSelection) {
|
||||
if builder.config.is_rust_llvm(target) {
|
||||
cargo.env("LLVM_RUSTLLVM", "1");
|
||||
|
|
@ -1665,7 +1669,7 @@ impl Step for CodegenBackend {
|
|||
cargo
|
||||
.arg("--manifest-path")
|
||||
.arg(builder.src.join(format!("compiler/rustc_codegen_{backend}/Cargo.toml")));
|
||||
rustc_cargo_env(builder, &mut cargo, target, compiler.stage);
|
||||
rustc_cargo_env(builder, &mut cargo, target);
|
||||
|
||||
// Ideally, we'd have a separate step for the individual codegen backends,
|
||||
// like we have in tests (test::CodegenGCC) but that would require a lot of restructuring.
|
||||
|
|
|
|||
|
|
@ -1757,6 +1757,10 @@ NOTE: if you're sure you want to do this, please open an issue as to why. In the
|
|||
cmd.arg("--host").arg(&*compiler.host.triple);
|
||||
cmd.arg("--llvm-filecheck").arg(builder.llvm_filecheck(builder.config.host_target));
|
||||
|
||||
if let Some(codegen_backend) = builder.config.default_codegen_backend(compiler.host) {
|
||||
cmd.arg("--codegen-backend").arg(&codegen_backend);
|
||||
}
|
||||
|
||||
if builder.build.config.llvm_enzyme {
|
||||
cmd.arg("--has-enzyme");
|
||||
}
|
||||
|
|
@ -1810,7 +1814,24 @@ NOTE: if you're sure you want to do this, please open an issue as to why. In the
|
|||
}
|
||||
|
||||
let mut flags = if is_rustdoc { Vec::new() } else { vec!["-Crpath".to_string()] };
|
||||
flags.push(format!("-Cdebuginfo={}", builder.config.rust_debuginfo_level_tests));
|
||||
flags.push(format!(
|
||||
"-Cdebuginfo={}",
|
||||
if suite == "codegen" {
|
||||
// codegen tests typically check LLVM IR and are sensitive to additional debuginfo.
|
||||
// So do not apply `rust.debuginfo-level-tests` for codegen tests.
|
||||
if builder.config.rust_debuginfo_level_tests
|
||||
!= crate::core::config::DebuginfoLevel::None
|
||||
{
|
||||
println!(
|
||||
"NOTE: ignoring `rust.debuginfo-level-tests={}` for codegen tests",
|
||||
builder.config.rust_debuginfo_level_tests
|
||||
);
|
||||
}
|
||||
crate::core::config::DebuginfoLevel::None
|
||||
} else {
|
||||
builder.config.rust_debuginfo_level_tests
|
||||
}
|
||||
));
|
||||
flags.extend(builder.config.cmd.compiletest_rustc_args().iter().map(|s| s.to_string()));
|
||||
|
||||
if suite != "mir-opt" {
|
||||
|
|
@ -3387,7 +3408,7 @@ impl Step for CodegenCranelift {
|
|||
cargo
|
||||
.arg("--manifest-path")
|
||||
.arg(builder.src.join("compiler/rustc_codegen_cranelift/build_system/Cargo.toml"));
|
||||
compile::rustc_cargo_env(builder, &mut cargo, target, compiler.stage);
|
||||
compile::rustc_cargo_env(builder, &mut cargo, target);
|
||||
|
||||
// Avoid incremental cache issues when changing rustc
|
||||
cargo.env("CARGO_BUILD_INCREMENTAL", "false");
|
||||
|
|
@ -3519,7 +3540,7 @@ impl Step for CodegenGCC {
|
|||
cargo
|
||||
.arg("--manifest-path")
|
||||
.arg(builder.src.join("compiler/rustc_codegen_gcc/build_system/Cargo.toml"));
|
||||
compile::rustc_cargo_env(builder, &mut cargo, target, compiler.stage);
|
||||
compile::rustc_cargo_env(builder, &mut cargo, target);
|
||||
add_cg_gcc_cargo_flags(&mut cargo, &gcc);
|
||||
|
||||
// Avoid incremental cache issues when changing rustc
|
||||
|
|
|
|||
|
|
@ -712,7 +712,11 @@ mod snapshot {
|
|||
[build] llvm <host>
|
||||
[build] rustc 0 <host> -> rustc 1 <host>
|
||||
");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn build_rustc_no_explicit_stage() {
|
||||
let ctx = TestCtx::new();
|
||||
insta::assert_snapshot!(
|
||||
ctx.config("build")
|
||||
.path("rustc")
|
||||
|
|
@ -1303,17 +1307,19 @@ mod snapshot {
|
|||
ctx.config("check")
|
||||
.path("compiler")
|
||||
.render_steps(), @r"
|
||||
[build] llvm <host>
|
||||
[check] rustc 0 <host> -> rustc 1 <host>
|
||||
[check] rustc 0 <host> -> cranelift 1 <host>
|
||||
[check] rustc 0 <host> -> gcc 1 <host>
|
||||
");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn check_rustc_no_explicit_stage() {
|
||||
let ctx = TestCtx::new();
|
||||
insta::assert_snapshot!(
|
||||
ctx.config("check")
|
||||
.path("rustc")
|
||||
.render_steps(), @r"
|
||||
[build] llvm <host>
|
||||
[check] rustc 0 <host> -> rustc 1 <host>
|
||||
");
|
||||
}
|
||||
|
|
@ -1333,7 +1339,6 @@ mod snapshot {
|
|||
.path("compiler")
|
||||
.stage(1)
|
||||
.render_steps(), @r"
|
||||
[build] llvm <host>
|
||||
[check] rustc 0 <host> -> rustc 1 <host>
|
||||
[check] rustc 0 <host> -> cranelift 1 <host>
|
||||
[check] rustc 0 <host> -> gcc 1 <host>
|
||||
|
|
@ -1465,7 +1470,6 @@ mod snapshot {
|
|||
.paths(&["library", "compiler"])
|
||||
.args(&args)
|
||||
.render_steps(), @r"
|
||||
[build] llvm <host>
|
||||
[check] rustc 0 <host> -> rustc 1 <host>
|
||||
[check] rustc 0 <host> -> cranelift 1 <host>
|
||||
[check] rustc 0 <host> -> gcc 1 <host>
|
||||
|
|
@ -1479,7 +1483,6 @@ mod snapshot {
|
|||
ctx.config("check")
|
||||
.path("miri")
|
||||
.render_steps(), @r"
|
||||
[build] llvm <host>
|
||||
[check] rustc 0 <host> -> rustc 1 <host>
|
||||
[check] rustc 0 <host> -> Miri 1 <host>
|
||||
");
|
||||
|
|
@ -1500,7 +1503,6 @@ mod snapshot {
|
|||
.path("miri")
|
||||
.stage(1)
|
||||
.render_steps(), @r"
|
||||
[build] llvm <host>
|
||||
[check] rustc 0 <host> -> rustc 1 <host>
|
||||
[check] rustc 0 <host> -> Miri 1 <host>
|
||||
");
|
||||
|
|
@ -1553,7 +1555,6 @@ mod snapshot {
|
|||
ctx.config("check")
|
||||
.path("rustc_codegen_cranelift")
|
||||
.render_steps(), @r"
|
||||
[build] llvm <host>
|
||||
[check] rustc 0 <host> -> rustc 1 <host>
|
||||
[check] rustc 0 <host> -> cranelift 1 <host>
|
||||
[check] rustc 0 <host> -> gcc 1 <host>
|
||||
|
|
@ -1567,7 +1568,6 @@ mod snapshot {
|
|||
ctx.config("check")
|
||||
.path("rust-analyzer")
|
||||
.render_steps(), @r"
|
||||
[build] llvm <host>
|
||||
[check] rustc 0 <host> -> rustc 1 <host>
|
||||
[check] rustc 0 <host> -> rust-analyzer 1 <host>
|
||||
");
|
||||
|
|
|
|||
|
|
@ -205,6 +205,8 @@ settings:
|
|||
on `wasm32-unknown-unknown` target because the target does not support the
|
||||
`proc-macro` crate type.
|
||||
- `needs-target-std` — ignores if target platform does not have std support.
|
||||
- `ignore-backends` — ignores the listed backends, separated by whitespace characters.
|
||||
- `needs-backends` — only runs the test if current codegen backend is listed.
|
||||
|
||||
The following directives will check LLVM support:
|
||||
|
||||
|
|
|
|||
|
|
@ -175,6 +175,36 @@ pub enum Sanitizer {
|
|||
Hwaddress,
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug, PartialEq)]
|
||||
pub enum CodegenBackend {
|
||||
Cranelift,
|
||||
Gcc,
|
||||
Llvm,
|
||||
}
|
||||
|
||||
impl<'a> TryFrom<&'a str> for CodegenBackend {
|
||||
type Error = &'static str;
|
||||
|
||||
fn try_from(value: &'a str) -> Result<Self, Self::Error> {
|
||||
match value.to_lowercase().as_str() {
|
||||
"cranelift" => Ok(Self::Cranelift),
|
||||
"gcc" => Ok(Self::Gcc),
|
||||
"llvm" => Ok(Self::Llvm),
|
||||
_ => Err("unknown backend"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl CodegenBackend {
|
||||
pub fn as_str(self) -> &'static str {
|
||||
match self {
|
||||
Self::Cranelift => "cranelift",
|
||||
Self::Gcc => "gcc",
|
||||
Self::Llvm => "llvm",
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Configuration for `compiletest` *per invocation*.
|
||||
///
|
||||
/// In terms of `bootstrap`, this means that `./x test tests/ui tests/run-make` actually correspond
|
||||
|
|
@ -651,6 +681,9 @@ pub struct Config {
|
|||
/// need `core` stubs in cross-compilation scenarios that do not otherwise want/need to
|
||||
/// `-Zbuild-std`. Used in e.g. ABI tests.
|
||||
pub minicore_path: Utf8PathBuf,
|
||||
|
||||
/// Current codegen backend used.
|
||||
pub codegen_backend: CodegenBackend,
|
||||
}
|
||||
|
||||
impl Config {
|
||||
|
|
@ -753,6 +786,7 @@ impl Config {
|
|||
profiler_runtime: Default::default(),
|
||||
diff_command: Default::default(),
|
||||
minicore_path: Default::default(),
|
||||
codegen_backend: CodegenBackend::Llvm,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@ use camino::{Utf8Path, Utf8PathBuf};
|
|||
use semver::Version;
|
||||
use tracing::*;
|
||||
|
||||
use crate::common::{Config, Debugger, FailMode, PassMode, RunFailMode, TestMode};
|
||||
use crate::common::{CodegenBackend, Config, Debugger, FailMode, PassMode, RunFailMode, TestMode};
|
||||
use crate::debuggers::{extract_cdb_version, extract_gdb_version};
|
||||
use crate::directives::auxiliary::{AuxProps, parse_and_update_aux};
|
||||
use crate::directives::needs::CachedNeedsConditions;
|
||||
|
|
@ -818,6 +818,7 @@ const KNOWN_DIRECTIVE_NAMES: &[&str] = &[
|
|||
"ignore-arm-unknown-linux-musleabihf",
|
||||
"ignore-auxiliary",
|
||||
"ignore-avr",
|
||||
"ignore-backends",
|
||||
"ignore-beta",
|
||||
"ignore-cdb",
|
||||
"ignore-compare-mode-next-solver",
|
||||
|
|
@ -907,6 +908,7 @@ const KNOWN_DIRECTIVE_NAMES: &[&str] = &[
|
|||
"min-llvm-version",
|
||||
"min-system-llvm-version",
|
||||
"needs-asm-support",
|
||||
"needs-backends",
|
||||
"needs-crate-type",
|
||||
"needs-deterministic-layouts",
|
||||
"needs-dlltool",
|
||||
|
|
@ -1669,6 +1671,8 @@ pub(crate) fn make_test_description<R: Read>(
|
|||
decision!(cfg::handle_only(config, ln));
|
||||
decision!(needs::handle_needs(&cache.needs, config, ln));
|
||||
decision!(ignore_llvm(config, path, ln));
|
||||
decision!(ignore_backends(config, path, ln));
|
||||
decision!(needs_backends(config, path, ln));
|
||||
decision!(ignore_cdb(config, ln));
|
||||
decision!(ignore_gdb(config, ln));
|
||||
decision!(ignore_lldb(config, ln));
|
||||
|
|
@ -1795,6 +1799,49 @@ fn ignore_lldb(config: &Config, line: &str) -> IgnoreDecision {
|
|||
IgnoreDecision::Continue
|
||||
}
|
||||
|
||||
fn ignore_backends(config: &Config, path: &Utf8Path, line: &str) -> IgnoreDecision {
|
||||
if let Some(backends_to_ignore) = config.parse_name_value_directive(line, "ignore-backends") {
|
||||
for backend in backends_to_ignore.split_whitespace().map(|backend| {
|
||||
match CodegenBackend::try_from(backend) {
|
||||
Ok(backend) => backend,
|
||||
Err(error) => {
|
||||
panic!("Invalid ignore-backends value `{backend}` in `{path}`: {error}")
|
||||
}
|
||||
}
|
||||
}) {
|
||||
if config.codegen_backend == backend {
|
||||
return IgnoreDecision::Ignore {
|
||||
reason: format!("{} backend is marked as ignore", backend.as_str()),
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
IgnoreDecision::Continue
|
||||
}
|
||||
|
||||
fn needs_backends(config: &Config, path: &Utf8Path, line: &str) -> IgnoreDecision {
|
||||
if let Some(needed_backends) = config.parse_name_value_directive(line, "needs-backends") {
|
||||
if !needed_backends
|
||||
.split_whitespace()
|
||||
.map(|backend| match CodegenBackend::try_from(backend) {
|
||||
Ok(backend) => backend,
|
||||
Err(error) => {
|
||||
panic!("Invalid needs-backends value `{backend}` in `{path}`: {error}")
|
||||
}
|
||||
})
|
||||
.any(|backend| config.codegen_backend == backend)
|
||||
{
|
||||
return IgnoreDecision::Ignore {
|
||||
reason: format!(
|
||||
"{} backend is not part of required backends",
|
||||
config.codegen_backend.as_str()
|
||||
),
|
||||
};
|
||||
}
|
||||
}
|
||||
IgnoreDecision::Continue
|
||||
}
|
||||
|
||||
fn ignore_llvm(config: &Config, path: &Utf8Path, line: &str) -> IgnoreDecision {
|
||||
if let Some(needed_components) =
|
||||
config.parse_name_value_directive(line, "needs-llvm-components")
|
||||
|
|
|
|||
|
|
@ -39,7 +39,7 @@ use walkdir::WalkDir;
|
|||
|
||||
use self::directives::{EarlyProps, make_test_description};
|
||||
use crate::common::{
|
||||
CompareMode, Config, Debugger, PassMode, TestMode, TestPaths, UI_EXTENSIONS,
|
||||
CodegenBackend, CompareMode, Config, Debugger, PassMode, TestMode, TestPaths, UI_EXTENSIONS,
|
||||
expected_output_path, output_base_dir, output_relative_path,
|
||||
};
|
||||
use crate::directives::DirectivesCache;
|
||||
|
|
@ -203,6 +203,12 @@ pub fn parse_config(args: Vec<String>) -> Config {
|
|||
"debugger",
|
||||
"only test a specific debugger in debuginfo tests",
|
||||
"gdb | lldb | cdb",
|
||||
)
|
||||
.optopt(
|
||||
"",
|
||||
"codegen-backend",
|
||||
"the codegen backend currently used",
|
||||
"CODEGEN BACKEND NAME",
|
||||
);
|
||||
|
||||
let (argv0, args_) = args.split_first().unwrap();
|
||||
|
|
@ -264,6 +270,15 @@ pub fn parse_config(args: Vec<String>) -> Config {
|
|||
|| directives::extract_llvm_version_from_binary(&matches.opt_str("llvm-filecheck")?),
|
||||
);
|
||||
|
||||
let codegen_backend = match matches.opt_str("codegen-backend").as_deref() {
|
||||
Some(backend) => match CodegenBackend::try_from(backend) {
|
||||
Ok(backend) => backend,
|
||||
Err(error) => panic!("invalid value `{backend}` for `--codegen-backend`: {error}"),
|
||||
},
|
||||
// By default, it's always llvm.
|
||||
None => CodegenBackend::Llvm,
|
||||
};
|
||||
|
||||
let run_ignored = matches.opt_present("ignored");
|
||||
let with_rustc_debug_assertions = matches.opt_present("with-rustc-debug-assertions");
|
||||
let with_std_debug_assertions = matches.opt_present("with-std-debug-assertions");
|
||||
|
|
@ -449,6 +464,8 @@ pub fn parse_config(args: Vec<String>) -> Config {
|
|||
diff_command: matches.opt_str("compiletest-diff-tool"),
|
||||
|
||||
minicore_path: opt_path(matches, "minicore-path"),
|
||||
|
||||
codegen_backend,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,11 +1,15 @@
|
|||
error: internal compiler error: compiler/rustc_mir_transform/src/validate.rs:LL:CC: broken MIR in Item(DefId) (after phase change to runtime-optimized) at bb0[1]:
|
||||
place (*(_2.0: *mut i32)) has deref as a later projection (it is only permitted as the first projection)
|
||||
--> tests/panic/mir-validation.rs:LL:CC
|
||||
|
|
||||
LL | *(tuple.0) = 1;
|
||||
| ^^^^^^^^^^^^^^
|
||||
|
||||
|
||||
thread 'rustc' panicked at compiler/rustc_mir_transform/src/validate.rs:LL:CC:
|
||||
broken MIR in Item(DefId) (after phase change to runtime-optimized) at bb0[1]:
|
||||
place (*(_2.0: *mut i32)) has deref as a later projection (it is only permitted as the first projection)
|
||||
Box<dyn Any>
|
||||
stack backtrace:
|
||||
|
||||
error: the compiler unexpectedly panicked. this is a bug.
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
@ -20,3 +24,5 @@ LL | extern "rust-call" fn call_once(self, args: Args) -> Self::Output;
|
|||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
|
||||
error: aborting due to 1 previous error
|
||||
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
// other architectures (including ARM and x86-64) use the prefix `.Lanon.`
|
||||
//@ only-linux
|
||||
//@ assembly-output: emit-asm
|
||||
//@ compile-flags: --crate-type=lib -Copt-level=3
|
||||
//@ compile-flags: --crate-type=lib -Copt-level=3 -Cllvm-args=-enable-global-merge=0
|
||||
//@ edition: 2024
|
||||
|
||||
use std::ffi::CStr;
|
||||
|
|
|
|||
28
tests/codegen/repeat-operand-zero-len.rs
Normal file
28
tests/codegen/repeat-operand-zero-len.rs
Normal file
|
|
@ -0,0 +1,28 @@
|
|||
//@ compile-flags: -Copt-level=1 -Cno-prepopulate-passes
|
||||
|
||||
// This test is here to hit the `Rvalue::Repeat` case in `codegen_rvalue_operand`.
|
||||
// It only applies when the resulting array is a ZST, so the test is written in
|
||||
// such a way as to keep MIR optimizations from seeing that fact and removing
|
||||
// the local and statement altogether. (At the time of writing, no other codegen
|
||||
// test hit that code path, nor did a stage 2 build of the compiler.)
|
||||
|
||||
#![crate_type = "lib"]
|
||||
|
||||
#[repr(transparent)]
|
||||
pub struct Wrapper<T, const N: usize>([T; N]);
|
||||
|
||||
// CHECK-LABEL: define {{.+}}do_repeat{{.+}}(i32 noundef %x)
|
||||
// CHECK-NEXT: start:
|
||||
// CHECK-NOT: alloca
|
||||
// CHECK-NEXT: ret void
|
||||
#[inline(never)]
|
||||
pub fn do_repeat<T: Copy, const N: usize>(x: T) -> Wrapper<T, N> {
|
||||
Wrapper([x; N])
|
||||
}
|
||||
|
||||
// CHECK-LABEL: @trigger_repeat_zero_len
|
||||
#[no_mangle]
|
||||
pub fn trigger_repeat_zero_len() -> Wrapper<u32, 0> {
|
||||
// CHECK: call void {{.+}}do_repeat{{.+}}(i32 noundef 4)
|
||||
do_repeat(4)
|
||||
}
|
||||
28
tests/codegen/repeat-operand-zst-elem.rs
Normal file
28
tests/codegen/repeat-operand-zst-elem.rs
Normal file
|
|
@ -0,0 +1,28 @@
|
|||
//@ compile-flags: -Copt-level=1 -Cno-prepopulate-passes
|
||||
|
||||
// This test is here to hit the `Rvalue::Repeat` case in `codegen_rvalue_operand`.
|
||||
// It only applies when the resulting array is a ZST, so the test is written in
|
||||
// such a way as to keep MIR optimizations from seeing that fact and removing
|
||||
// the local and statement altogether. (At the time of writing, no other codegen
|
||||
// test hit that code path, nor did a stage 2 build of the compiler.)
|
||||
|
||||
#![crate_type = "lib"]
|
||||
|
||||
#[repr(transparent)]
|
||||
pub struct Wrapper<T, const N: usize>([T; N]);
|
||||
|
||||
// CHECK-LABEL: define {{.+}}do_repeat{{.+}}()
|
||||
// CHECK-NEXT: start:
|
||||
// CHECK-NOT: alloca
|
||||
// CHECK-NEXT: ret void
|
||||
#[inline(never)]
|
||||
pub fn do_repeat<T: Copy, const N: usize>(x: T) -> Wrapper<T, N> {
|
||||
Wrapper([x; N])
|
||||
}
|
||||
|
||||
// CHECK-LABEL: @trigger_repeat_zst_elem
|
||||
#[no_mangle]
|
||||
pub fn trigger_repeat_zst_elem() -> Wrapper<(), 8> {
|
||||
// CHECK: call void {{.+}}do_repeat{{.+}}()
|
||||
do_repeat(())
|
||||
}
|
||||
24
tests/ui/cfg/crt-static-with-target-features-works.rs
Normal file
24
tests/ui/cfg/crt-static-with-target-features-works.rs
Normal file
|
|
@ -0,0 +1,24 @@
|
|||
// Test to ensure that specifying a value for crt-static in target features
|
||||
// does not result in skipping the features following it.
|
||||
// This is a regression test for #144143
|
||||
|
||||
//@ add-core-stubs
|
||||
//@ needs-llvm-components: x86
|
||||
//@ compile-flags: --target=x86_64-unknown-linux-gnu
|
||||
//@ compile-flags: -Ctarget-feature=+crt-static,+avx2
|
||||
|
||||
#![crate_type = "rlib"]
|
||||
#![feature(no_core, rustc_attrs, lang_items)]
|
||||
#![no_core]
|
||||
|
||||
extern crate minicore;
|
||||
use minicore::*;
|
||||
|
||||
#[rustc_builtin_macro]
|
||||
macro_rules! compile_error {
|
||||
() => {};
|
||||
}
|
||||
|
||||
#[cfg(target_feature = "avx2")]
|
||||
compile_error!("+avx2");
|
||||
//~^ ERROR: +avx2
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
error: +avx2
|
||||
--> $DIR/crt-static-with-target-features-works.rs:23:1
|
||||
|
|
||||
LL | compile_error!("+avx2");
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: aborting due to 1 previous error
|
||||
|
||||
|
|
@ -21,6 +21,8 @@ pub fn f(a: u32) -> u32 {
|
|||
}
|
||||
bb1 = {
|
||||
Call(RET = f(1), ReturnTo(bb2), UnwindTerminate(ReasonAbi))
|
||||
//~^ ERROR broken MIR in Item
|
||||
//~| ERROR encountered critical edge in `Call` terminator
|
||||
}
|
||||
|
||||
bb2 = {
|
||||
|
|
@ -29,5 +31,3 @@ pub fn f(a: u32) -> u32 {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
//~? RAW encountered critical edge in `Call` terminator
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue