Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
cae926b
Revert "Remove restrictions on small enum statements such as `Order`,…
dianqk Sep 14, 2025
23ec2cf
Revert "Add a workaround for the `TailDuplicator` compile time overhead"
dianqk Sep 14, 2025
72825b9
Mark code only used in nightly as nightly only
Hoverbear Mar 27, 2026
6ea175c
Remove unused code
jyn514 Mar 30, 2026
b7bd207
Avoid projection-only constraint suggestions for inherent associated …
cijiugechu Apr 13, 2026
e885842
Add issue 155204 regression test
cijiugechu Apr 13, 2026
28b0ef6
Add FIXME
cijiugechu Apr 14, 2026
eb6eed4
Make `//@ skip-filecheck` a normal compiletest directive
Zalathar Apr 21, 2026
1e8cd1f
Support `//@ skip-filecheck` in codegen and assembly tests
Zalathar Apr 21, 2026
8172f47
Remove non-working code for "running" mir-opt tests
Zalathar Apr 22, 2026
1a3c6b4
Don't pass `local_pm` to `compile_test_general`
Zalathar Apr 22, 2026
84cd23b
c-variadic: rename `VaList::arg` to `VaList::next_arg`
folkertdev Apr 21, 2026
f6b8f0b
rustc_llvm: update opt-level handling for LLVM 23
durin42 Apr 22, 2026
110e67c
Expand `Path::is_empty` docs
ChrisDenton Apr 22, 2026
e722ba5
improved assumptions relating isqrt (squashed)
Apersoma Apr 22, 2026
328d053
c-variadic: add mips assembly test
folkertdev Apr 22, 2026
e9ab558
va_arg: use `emit_ptr_va_arg` for mips
folkertdev Feb 13, 2026
032b666
Rollup merge of #146544 - dianqk:rm-workaround, r=wesleywiser
JonathanBrouwer Apr 23, 2026
2803453
Rollup merge of #154819 - cijiugechu:fix-next-solver-inherent-iat-ice…
JonathanBrouwer Apr 23, 2026
04bcb39
Rollup merge of #155265 - Apersoma:isqrt-smarter, r=jhpratt,tgross35
JonathanBrouwer Apr 23, 2026
6cc506c
Rollup merge of #152576 - folkertdev:mips-va-arg, r=tgross35
JonathanBrouwer Apr 23, 2026
421a94f
Rollup merge of #154481 - ferrocene:hoverbear/flag-off-unused-code, r…
JonathanBrouwer Apr 23, 2026
d289cc7
Rollup merge of #155614 - folkertdev:rename-next-arg, r=tgross35
JonathanBrouwer Apr 23, 2026
610bfad
Rollup merge of #155630 - Zalathar:skip-filecheck, r=jieyouxu
JonathanBrouwer Apr 23, 2026
333f033
Rollup merge of #155641 - Zalathar:no-run-mir-opt, r=jieyouxu
JonathanBrouwer Apr 23, 2026
f586047
Rollup merge of #155652 - ChrisDenton:empty-docs, r=jhpratt
JonathanBrouwer Apr 23, 2026
0fa807c
Rollup merge of #155656 - durin42:llvm-23-back-in-kansas, r=nikic
JonathanBrouwer Apr 23, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions compiler/rustc_abi/src/callconv.rs
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ impl HomogeneousAggregate {
/// Try to combine two `HomogeneousAggregate`s, e.g. from two fields in
/// the same `struct`. Only succeeds if only one of them has any data,
/// or both units are identical.
#[cfg(feature = "nightly")]
fn merge(self, other: HomogeneousAggregate) -> Result<HomogeneousAggregate, Heterogeneous> {
match (self, other) {
(x, HomogeneousAggregate::NoData) | (HomogeneousAggregate::NoData, x) => Ok(x),
Expand Down
23 changes: 19 additions & 4 deletions compiler/rustc_codegen_llvm/src/va_arg.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1171,14 +1171,29 @@ pub(super) fn emit_va_arg<'ll, 'tcx>(
AllowHigherAlign::Yes,
ForceRightAdjust::No,
),
Arch::Mips | Arch::Mips32r6 | Arch::Mips64 | Arch::Mips64r6 => emit_ptr_va_arg(
bx,
addr,
target_ty,
PassMode::Direct,
match &target.llvm_abiname {
LlvmAbi::N32 | LlvmAbi::N64 => SlotSize::Bytes8,
LlvmAbi::O32 => SlotSize::Bytes4,
other => bug!("unexpected LLVM ABI {other}"),
},
AllowHigherAlign::Yes,
// In big-endian mode the actual value is stored in the right side of the slot, meaning
// that when the value is smaller than a slot, we need to adjust the pointer we read
// to somewhere in the middle of the slot.
match bx.tcx().sess.target.endian {
Endian::Big => ForceRightAdjust::Yes,
Endian::Little => ForceRightAdjust::No,
},
),

Arch::Bpf => bug!("bpf does not support c-variadic functions"),
Arch::SpirV => bug!("spirv does not support c-variadic functions"),

Arch::Mips | Arch::Mips32r6 | Arch::Mips64 | Arch::Mips64r6 => {
// FIXME: port MipsTargetLowering::lowerVAARG.
bx.va_arg(addr.immediate(), bx.cx.layout_of(target_ty).llvm_type(bx.cx))
}
Arch::Sparc | Arch::Avr | Arch::M68k | Arch::Msp430 => {
// Clang uses the LLVM implementation for these architectures.
bx.va_arg(addr.immediate(), bx.cx.layout_of(target_ty).llvm_type(bx.cx))
Expand Down
2 changes: 0 additions & 2 deletions compiler/rustc_index/src/bit_set.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,4 @@
use std::marker::PhantomData;
#[cfg(not(feature = "nightly"))]
use std::mem;
use std::ops::{Bound, Range, RangeBounds};
use std::rc::Rc;
use std::{fmt, iter, slice};
Expand Down
7 changes: 7 additions & 0 deletions compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -165,10 +165,17 @@ static OptimizationLevel fromRust(LLVMRustPassBuilderOptLevel Level) {
return OptimizationLevel::O2;
case LLVMRustPassBuilderOptLevel::O3:
return OptimizationLevel::O3;
#if LLVM_VERSION_GE(23, 0)
case LLVMRustPassBuilderOptLevel::Os:
return OptimizationLevel::O2;
case LLVMRustPassBuilderOptLevel::Oz:
return OptimizationLevel::O2;
#else
case LLVMRustPassBuilderOptLevel::Os:
return OptimizationLevel::Os;
case LLVMRustPassBuilderOptLevel::Oz:
return OptimizationLevel::Oz;
#endif
default:
report_fatal_error("Bad PassBuilderOptLevel.");
}
Expand Down
52 changes: 6 additions & 46 deletions compiler/rustc_mir_transform/src/unreachable_enum_branching.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,7 @@ use rustc_abi::Variants;
use rustc_data_structures::fx::FxHashSet;
use rustc_middle::bug;
use rustc_middle::mir::{
BasicBlock, BasicBlockData, BasicBlocks, Body, Local, Operand, Rvalue, StatementKind,
TerminatorKind,
BasicBlockData, Body, Local, Operand, Rvalue, StatementKind, TerminatorKind,
};
use rustc_middle::ty::layout::TyAndLayout;
use rustc_middle::ty::{Ty, TyCtxt};
Expand Down Expand Up @@ -125,43 +124,10 @@ impl<'tcx> crate::MirPass<'tcx> for UnreachableEnumBranching {
unreachable_targets.push(index);
}
}
let otherwise_is_empty_unreachable =
body.basic_blocks[targets.otherwise()].is_empty_unreachable();
fn check_successors(basic_blocks: &BasicBlocks<'_>, bb: BasicBlock) -> bool {
// After resolving https://github.com/llvm/llvm-project/issues/78578,
// We can remove this check.
// The main issue here is that `early-tailduplication` causes compile time overhead
// and potential performance problems.
// Simply put, when encounter a switch (indirect branch) statement,
// `early-tailduplication` tries to duplicate the switch branch statement with BB
// into (each) predecessors. This makes CFG very complex.
// We can understand it as it transforms the following code
// ```rust
// match a { ... many cases };
// match b { ... many cases };
// ```
// into
// ```rust
// match a { ... many match b { goto BB cases } }
// ... BB cases
// ```
// Abandon this transformation when it is possible (the best effort)
// to encounter the problem.
let mut successors = basic_blocks[bb].terminator().successors();
let Some(first_successor) = successors.next() else { return true };
if successors.next().is_some() {
return true;
}
if let TerminatorKind::SwitchInt { .. } =
&basic_blocks[first_successor].terminator().kind
{
return false;
};
true
}

// If and only if there is a variant that does not have a branch set, change the
// current of otherwise as the variant branch and set otherwise to unreachable. It
// transforms following code
// transforms the following code
// ```rust
// match c {
// Ordering::Less => 1,
Expand All @@ -177,22 +143,16 @@ impl<'tcx> crate::MirPass<'tcx> for UnreachableEnumBranching {
// Ordering::Greater => 3,
// }
// ```
let otherwise_is_last_variant = !otherwise_is_empty_unreachable
&& allowed_variants.len() == 1
// Despite the LLVM issue, we hope that small enum can still be transformed.
// This is valuable for both `a <= b` and `if let Some/Ok(v)`.
&& (targets.all_targets().len() <= 3
|| check_successors(&body.basic_blocks, targets.otherwise()));
let replace_otherwise_to_unreachable = otherwise_is_last_variant
|| (!otherwise_is_empty_unreachable && allowed_variants.is_empty());

let replace_otherwise_to_unreachable = allowed_variants.len() <= 1
&& !body.basic_blocks[targets.otherwise()].is_empty_unreachable();
if unreachable_targets.is_empty() && !replace_otherwise_to_unreachable {
continue;
}

let unreachable_block = patch.unreachable_no_cleanup_block();
let mut targets = targets.clone();
if replace_otherwise_to_unreachable {
let otherwise_is_last_variant = allowed_variants.len() == 1;
if otherwise_is_last_variant {
// We have checked that `allowed_variants` has only one element.
#[allow(rustc::potential_query_instability)]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -606,6 +606,10 @@ impl<T> Trait<T> for X {
ty: Ty<'tcx>,
) -> bool {
let tcx = self.tcx;
// FIXME(inherent_associated_types): Extend this to support `ty::Inherent`, too.
if !matches!(proj_ty.kind, ty::AliasTyKind::Projection { .. }) {
return false;
}
let Some(body_owner_def_id) = body_owner_def_id else {
return false;
};
Expand Down
8 changes: 4 additions & 4 deletions library/core/src/ffi/va_list.rs
Original file line number Diff line number Diff line change
Expand Up @@ -204,7 +204,7 @@ crate::cfg_select! {
/// unsafe fn vmy_func(count: u32, mut ap: VaList<'_>) -> i32 {
/// let mut sum = 0;
/// for _ in 0..count {
/// sum += unsafe { ap.arg::<i32>() };
/// sum += unsafe { ap.next_arg::<i32>() };
/// }
/// sum
/// }
Expand All @@ -213,7 +213,7 @@ crate::cfg_select! {
/// assert_eq!(unsafe { my_func(3, 42i32, -7i32, 20i32) }, 55);
/// ```
///
/// The [`VaList::arg`] method reads the next argument from the variable argument list,
/// The [`VaList::next_arg`] method reads the next argument from the variable argument list,
/// and is equivalent to C `va_arg`.
///
/// Cloning a `VaList` performs the equivalent of C `va_copy`, producing an independent cursor
Expand Down Expand Up @@ -284,7 +284,7 @@ mod sealed {
impl<T> Sealed for *const T {}
}

/// Types that are valid to read using [`VaList::arg`].
/// Types that are valid to read using [`VaList::next_arg`].
///
/// This trait is implemented for primitive types that have a variable argument application-binary
/// interface (ABI) on the current platform. It is always implemented for:
Expand Down Expand Up @@ -391,7 +391,7 @@ impl<'f> VaList<'f> {
/// are no more variable arguments, is unsound.
#[inline] // Avoid codegen when not used to help backends that don't support VaList.
#[rustc_const_unstable(feature = "const_c_variadic", issue = "151787")]
pub const unsafe fn arg<T: VaArgSafe>(&mut self) -> T {
pub const unsafe fn next_arg<T: VaArgSafe>(&mut self) -> T {
// SAFETY: the caller must uphold the safety contract for `va_arg`.
unsafe { va_arg(self) }
}
Expand Down
30 changes: 0 additions & 30 deletions library/core/src/num/imp/int_sqrt.rs
Original file line number Diff line number Diff line change
Expand Up @@ -41,36 +41,6 @@ pub(in crate::num) const fn u8(n: u8) -> u8 {
U8_ISQRT_WITH_REMAINDER[n as usize].0
}

/// Generates an `i*` function that returns the [integer square root](
/// https://en.wikipedia.org/wiki/Integer_square_root) of any **nonnegative**
/// input of a specific signed integer type.
macro_rules! signed_fn {
($SignedT:ident, $UnsignedT:ident) => {
/// Returns the [integer square root](
/// https://en.wikipedia.org/wiki/Integer_square_root) of any
/// **nonnegative**
#[doc = concat!("[`", stringify!($SignedT), "`](prim@", stringify!($SignedT), ")")]
/// input.
///
/// # Safety
///
/// This results in undefined behavior when the input is negative.
#[must_use = "this returns the result of the operation, \
without modifying the original"]
#[inline]
pub(in crate::num) const unsafe fn $SignedT(n: $SignedT) -> $SignedT {
debug_assert!(n >= 0, "Negative input inside `isqrt`.");
$UnsignedT(n as $UnsignedT) as $SignedT
}
};
}

signed_fn!(i8, u8);
signed_fn!(i16, u16);
signed_fn!(i32, u32);
signed_fn!(i64, u64);
signed_fn!(i128, u128);

/// Generates a `u*` function that returns the [integer square root](
/// https://en.wikipedia.org/wiki/Integer_square_root) of any input of
/// a specific unsigned integer type.
Expand Down
15 changes: 4 additions & 11 deletions library/core/src/num/int_macros.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1933,10 +1933,9 @@ macro_rules! int_impl {
if self < 0 {
None
} else {
// SAFETY: Input is nonnegative in this `else` branch.
let result = unsafe {
imp::int_sqrt::$ActualT(self as $ActualT) as $SelfT
};
// The upper bound of `$UnsignedT::MAX.isqrt()` told to the compiler
// in the unsigned function also tells it that `result >= 0`
let result = self.cast_unsigned().isqrt().cast_signed();

// Inform the optimizer what the range of outputs is. If
// testing `core` crashes with no panic message and a
Expand All @@ -1950,15 +1949,9 @@ macro_rules! int_impl {
// `[0, <$ActualT>::MAX]`, sqrt(n) will be bounded by
// `[sqrt(0), sqrt(<$ActualT>::MAX)]`.
unsafe {
// SAFETY: `<$ActualT>::MAX` is nonnegative.
const MAX_RESULT: $SelfT = unsafe {
imp::int_sqrt::$ActualT(<$ActualT>::MAX) as $SelfT
};

crate::hint::assert_unchecked(result >= 0);
const MAX_RESULT: $SelfT = <$SelfT>::MAX.cast_unsigned().isqrt().cast_signed();
crate::hint::assert_unchecked(result <= MAX_RESULT);
}

Some(result)
}
}
Expand Down
25 changes: 22 additions & 3 deletions library/core/src/num/uint_macros.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3682,7 +3682,7 @@ macro_rules! uint_impl {
without modifying the original"]
#[inline]
pub const fn isqrt(self) -> Self {
let result = imp::int_sqrt::$ActualT(self as $ActualT) as $SelfT;
let result = imp::int_sqrt::$ActualT(self as $ActualT) as Self;

// Inform the optimizer what the range of outputs is. If testing
// `core` crashes with no panic message and a `num::int_sqrt::u*`
Expand All @@ -3693,10 +3693,29 @@ macro_rules! uint_impl {
// function, which means that increasing the input will never
// cause the output to decrease. Thus, since the input for unsigned
// integers is bounded by `[0, <$ActualT>::MAX]`, sqrt(n) will be
// bounded by `[sqrt(0), sqrt(<$ActualT>::MAX)]`.
// bounded by `[sqrt(0), sqrt(<$ActualT>::MAX)]` and bounding the
// input by `[1, <$ActualT>::MAX]` bounds sqrt(n) by
// `[sqrt(1), sqrt(<$ActualT>::MAX)]`.
unsafe {
const MAX_RESULT: $SelfT = imp::int_sqrt::$ActualT(<$ActualT>::MAX) as $SelfT;
crate::hint::assert_unchecked(result <= MAX_RESULT);
crate::hint::assert_unchecked(result <= MAX_RESULT)
}

if self >= 1 {
// SAFETY: The above statements about monotonicity also apply here.
// Since the input in this branch is bounded by `[1, <$ActualT>::MAX]`,
// sqrt(n) is bounded by `[sqrt(1), sqrt(<$ActualT>::MAX)]`, and
// `sqrt(1) == 1`.
unsafe { crate::hint::assert_unchecked(result >= 1) }
}

// SAFETY: the isqrt implementation returns the square root and rounds down,
// meaning `result * result <= self`. This implies `result <= self`.
// The compiler needs both to optimize for both.
// `result * result <= self` implies the multiplication will not overflow.
unsafe {
crate::hint::assert_unchecked(result.unchecked_mul(result) <= self);
crate::hint::assert_unchecked(result <= self);
}

result
Expand Down
4 changes: 4 additions & 0 deletions library/std/src/path.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2828,6 +2828,10 @@ impl Path {

/// Checks whether the `Path` is empty.
///
/// Passing an empty path to most OS filesystem APIs will always result in an error.
///
/// [Pushing][PathBuf::push] an empty path to an existing path will append a directory separator unless it already ends with a separator or the existing path is itself empty.
///
/// # Examples
///
/// ```
Expand Down
2 changes: 2 additions & 0 deletions src/doc/rustc-dev-guide/src/tests/directives.md
Original file line number Diff line number Diff line change
Expand Up @@ -326,6 +326,8 @@ See [Pretty-printer](compiletest.md#pretty-printer-tests).
The following directives affect how certain command-line tools are invoked, in
test suites that use those tools:

- `skip-filecheck` avoids running LLVM's `FileCheck` tool in tests that would normally run it to check output.
- Used by codegen tests, assembly tests, and mir-opt tests.
- `filecheck-flags` adds extra flags when running LLVM's `FileCheck` tool.
- Used by [codegen tests](compiletest.md#codegen-tests),
[assembly tests](compiletest.md#assembly-tests), and
Expand Down
2 changes: 1 addition & 1 deletion src/doc/unstable-book/src/language-features/c-variadic.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ defined in Rust. They may be called both from within Rust and via FFI.
pub unsafe extern "C" fn add(n: usize, mut args: ...) -> usize {
let mut sum = 0;
for _ in 0..n {
sum += args.arg::<usize>();
sum += args.next_arg::<usize>();
}
sum
}
Expand Down
5 changes: 4 additions & 1 deletion src/tools/compiletest/src/directives.rs
Original file line number Diff line number Diff line change
Expand Up @@ -195,6 +195,9 @@ pub(crate) struct TestProps {
/// Extra flags to pass to `llvm-cov` when producing coverage reports.
/// Only used by the "coverage-run" test mode.
pub(crate) llvm_cov_flags: Vec<String>,
/// Don't run LLVM's `filecheck` tool to check compiler output,
/// in tests that would normally run it.
pub(crate) skip_filecheck: bool,
/// Extra flags to pass to LLVM's `filecheck` tool, in tests that use it.
pub(crate) filecheck_flags: Vec<String>,
/// Don't automatically insert any `--check-cfg` args
Expand Down Expand Up @@ -308,6 +311,7 @@ impl TestProps {
mir_unit_test: None,
remap_src_base: false,
llvm_cov_flags: vec![],
skip_filecheck: false,
filecheck_flags: vec![],
no_auto_check_cfg: false,
add_minicore: false,
Expand Down Expand Up @@ -438,7 +442,6 @@ impl TestProps {
let check_no_run = |s| match (config.mode, s) {
(TestMode::Ui, _) => (),
(TestMode::Crashes, _) => (),
(TestMode::Codegen, "build-pass") => (),
(mode, _) => panic!("`{s}` directive is not supported in `{mode}` tests"),
};
let pass_mode = if config.parse_name_directive(ln, "check-pass") {
Expand Down
1 change: 1 addition & 0 deletions src/tools/compiletest/src/directives/directive_names.rs
Original file line number Diff line number Diff line change
Expand Up @@ -286,6 +286,7 @@ pub(crate) const KNOWN_DIRECTIVE_NAMES: &[&str] = &[
"rustc-env",
"rustfix-only-machine-applicable",
"should-fail",
"skip-filecheck",
"stderr-per-bitwidth",
"test-mir-pass",
"unique-doc-out-dir",
Expand Down
14 changes: 13 additions & 1 deletion src/tools/compiletest/src/directives/handlers.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use std::collections::HashMap;
use std::sync::{Arc, LazyLock};

use crate::common::Config;
use crate::common::{Config, TestMode};
use crate::directives::{
DirectiveLine, NormalizeKind, NormalizeRule, TestProps, parse_and_update_aux,
parse_edition_range, split_flags,
Expand Down Expand Up @@ -312,6 +312,18 @@ fn make_directive_handlers_map() -> HashMap<&'static str, Handler> {
props.llvm_cov_flags.extend(split_flags(&flags));
}
}),
handler("skip-filecheck", |config, ln, props| {
let directive_name = ln.name;
// FIXME(Zalathar): Someday we should add unified support for declaring
// and checking which modes are supported by each directive.
if !matches!(config.mode, TestMode::Assembly | TestMode::Codegen | TestMode::MirOpt) {
panic!(
"directive `//@ {directive_name}` is not supported by this test suite (mode: {mode:?})",
mode = config.mode
);
}
config.set_name_directive(ln, directive_name, &mut props.skip_filecheck);
}),
handler(FILECHECK_FLAGS, |config, ln, props| {
if let Some(flags) = config.parse_name_value_directive(ln, FILECHECK_FLAGS) {
props.filecheck_flags.extend(split_flags(&flags));
Expand Down
Loading
Loading