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:
bors 2025-07-20 13:52:48 +00:00
commit 0864097cd3
31 changed files with 350 additions and 88 deletions

View file

@ -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

View file

@ -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

View file

@ -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) {

View file

@ -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
///

View file

@ -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

View file

@ -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(

View file

@ -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)]

View file

@ -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)
}

View file

@ -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(

View file

@ -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
///

View file

@ -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
///

View file

@ -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]

View file

@ -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.

View file

@ -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 {}

View file

@ -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!

View file

@ -2651,7 +2651,6 @@ impl str {
/// you're trying to parse into.
///
/// `parse` can parse into any type that implements the [`FromStr`] trait.
///
/// # Errors
///

View file

@ -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);

View file

@ -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.

View file

@ -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

View file

@ -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>
");

View file

@ -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:

View file

@ -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,
}
}

View file

@ -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")

View file

@ -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,
}
}

View file

@ -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

View file

@ -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;

View 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)
}

View 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(())
}

View 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

View file

@ -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

View file

@ -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