From e0d9940c1e44a3336de50484288921a84758ee9b Mon Sep 17 00:00:00 2001 From: Taiki Endo Date: Sat, 7 Mar 2026 21:53:18 +0900 Subject: [PATCH 001/183] rustc_codegen_ssa: Define ELF flag value for sparc-unknown-linux-gnu --- compiler/rustc_codegen_ssa/src/back/metadata.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/compiler/rustc_codegen_ssa/src/back/metadata.rs b/compiler/rustc_codegen_ssa/src/back/metadata.rs index 8a2a6823fdf4b..4fe05cbfb5b46 100644 --- a/compiler/rustc_codegen_ssa/src/back/metadata.rs +++ b/compiler/rustc_codegen_ssa/src/back/metadata.rs @@ -401,6 +401,7 @@ pub(super) fn elf_e_flags(architecture: Architecture, sess: &Session) -> u32 { _ => EF_PPC64_ABI_UNKNOWN, } } + Architecture::Sparc32Plus => elf::EF_SPARC_32PLUS, _ => 0, } } From 7463a85ad01485a2a998139db136007945e6859e Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Sun, 15 Mar 2026 17:16:03 -0500 Subject: [PATCH 002/183] ci: Bump all actions to latest --- .../.github/workflows/main.yaml | 28 +++++++++---------- .../.github/workflows/publish.yaml | 3 +- 2 files changed, 15 insertions(+), 16 deletions(-) diff --git a/library/compiler-builtins/.github/workflows/main.yaml b/library/compiler-builtins/.github/workflows/main.yaml index 261b1619f1c5f..e8e600b6c2a3c 100644 --- a/library/compiler-builtins/.github/workflows/main.yaml +++ b/library/compiler-builtins/.github/workflows/main.yaml @@ -28,7 +28,7 @@ jobs: extensive_matrix: ${{ steps.script.outputs.extensive_matrix }} may_skip_libm_ci: ${{ steps.script.outputs.may_skip_libm_ci }} steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v6 with: fetch-depth: 500 - name: Fetch pull request ref @@ -121,7 +121,7 @@ jobs: if: matrix.os == 'ubuntu-24.04-ppc64le' || matrix.os == 'ubuntu-24.04-s390x' run: sudo apt-get update && sudo apt-get install -y rustup - - uses: actions/checkout@v4 + - uses: actions/checkout@v6 - name: Install Rust (rustup) shell: bash run: | @@ -138,19 +138,19 @@ jobs: with: key: ${{ matrix.target }} - name: Cache Docker layers - uses: actions/cache@v4 + uses: actions/cache@v5 if: matrix.os == 'ubuntu-24.04' with: path: /tmp/.buildx-cache key: ${{ matrix.target }}-buildx-${{ github.sha }} restore-keys: ${{ matrix.target }}-buildx- # Configure buildx to use Docker layer caching - - uses: docker/setup-buildx-action@v3 + - uses: docker/setup-buildx-action@v4 if: matrix.os == 'ubuntu-24.04' - name: Cache compiler-rt id: cache-compiler-rt - uses: actions/cache@v4 + uses: actions/cache@v5 with: path: compiler-rt key: ${{ runner.os }}-compiler-rt-${{ hashFiles('ci/download-compiler-rt.sh') }} @@ -199,7 +199,7 @@ jobs: runs-on: ubuntu-24.04 timeout-minutes: 10 steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v6 # Unlike rustfmt, stable clippy does not work on code with nightly features. - name: Install nightly `clippy` run: | @@ -216,7 +216,7 @@ jobs: runs-on: ubuntu-24.04 timeout-minutes: 10 steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v6 - name: Install Rust run: | rustup update nightly --no-self-update @@ -237,7 +237,7 @@ jobs: runs-on: ubuntu-24.04 timeout-minutes: 10 steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v6 - name: Install Rust run: | rustup update nightly --no-self-update @@ -263,7 +263,7 @@ jobs: os: ubuntu-24.04-arm runs-on: ${{ matrix.os }} steps: - - uses: actions/checkout@master + - uses: actions/checkout@v6 - uses: taiki-e/install-action@cargo-binstall - name: Set up dependencies @@ -281,7 +281,7 @@ jobs: run: ./ci/bench-icount.sh ${{ matrix.target }} - name: Upload the benchmark baseline - uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@v6 with: name: ${{ env.BASELINE_NAME }} path: ${{ env.BASELINE_NAME }}.tar.xz @@ -299,7 +299,7 @@ jobs: runs-on: ubuntu-24.04 timeout-minutes: 10 steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v6 - name: Install Rust (rustup) # FIXME(ci): not working in the 2026-02-11 nightly # https://rust-lang.zulipchat.com/#narrow/channel/269128-miri/topic/build-script-build.20contains.20outdated.20or.20invalid.20JSON/with/573426109 @@ -317,7 +317,7 @@ jobs: env: RUSTFLAGS: # No need to check warnings on old MSRV, unset `-Dwarnings` steps: - - uses: actions/checkout@master + - uses: actions/checkout@v6 - name: Install Rust run: | msrv="$(perl -ne 'print if s/rust-version\s*=\s*"(.*)"/\1/g' libm/Cargo.toml)" @@ -335,7 +335,7 @@ jobs: runs-on: ubuntu-24.04 timeout-minutes: 10 steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v6 - name: Install nightly `rustfmt` run: rustup set profile minimal && rustup default nightly && rustup component add rustfmt - run: cargo fmt -- --check @@ -358,7 +358,7 @@ jobs: env: TO_TEST: ${{ matrix.to_test }} steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v6 - name: Install Rust run: | rustup update nightly --no-self-update diff --git a/library/compiler-builtins/.github/workflows/publish.yaml b/library/compiler-builtins/.github/workflows/publish.yaml index d6f1dc398e8ec..1f1cbf7c2a253 100644 --- a/library/compiler-builtins/.github/workflows/publish.yaml +++ b/library/compiler-builtins/.github/workflows/publish.yaml @@ -12,8 +12,7 @@ jobs: name: Release-plz runs-on: ubuntu-24.04 steps: - - name: Checkout repository - uses: actions/checkout@v4 + - uses: actions/checkout@v6 with: fetch-depth: 0 - name: Install Rust (rustup) From 8d51ad1eac2a3e38b5d16b4066931f79f8ad22ae Mon Sep 17 00:00:00 2001 From: MarcoIeni <11428655+MarcoIeni@users.noreply.github.com> Date: Mon, 16 Mar 2026 17:26:40 +0100 Subject: [PATCH 003/183] publish via trusted publishing --- library/compiler-builtins/.github/workflows/publish.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/library/compiler-builtins/.github/workflows/publish.yaml b/library/compiler-builtins/.github/workflows/publish.yaml index 1f1cbf7c2a253..b720d765568f9 100644 --- a/library/compiler-builtins/.github/workflows/publish.yaml +++ b/library/compiler-builtins/.github/workflows/publish.yaml @@ -11,6 +11,7 @@ jobs: release-plz: name: Release-plz runs-on: ubuntu-24.04 + environment: publish steps: - uses: actions/checkout@v6 with: @@ -18,7 +19,6 @@ jobs: - name: Install Rust (rustup) run: rustup update nightly --no-self-update && rustup default nightly - name: Run release-plz - uses: MarcoIeni/release-plz-action@v0.5 + uses: release-plz/action@v0.5 env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - CARGO_REGISTRY_TOKEN: ${{ secrets.CARGO_REGISTRY_TOKEN }} From f6382501f9cb9e2630f68eb2c63172df353fdc4b Mon Sep 17 00:00:00 2001 From: Folkert de Vries Date: Sat, 14 Mar 2026 17:56:46 +0100 Subject: [PATCH 004/183] export `__mulsi3` on `m68k` --- .../compiler-builtins/src/int/mul.rs | 57 ++++++++++++++++++- .../compiler-builtins/src/lib.rs | 3 - .../compiler-builtins/src/riscv.rs | 50 ---------------- 3 files changed, 55 insertions(+), 55 deletions(-) delete mode 100644 library/compiler-builtins/compiler-builtins/src/riscv.rs diff --git a/library/compiler-builtins/compiler-builtins/src/int/mul.rs b/library/compiler-builtins/compiler-builtins/src/int/mul.rs index 040c69342d148..7db09beb89e83 100644 --- a/library/compiler-builtins/compiler-builtins/src/int/mul.rs +++ b/library/compiler-builtins/compiler-builtins/src/int/mul.rs @@ -98,11 +98,63 @@ impl_signed_mulo!(i64_overflowing_mul, i64, u64); impl_signed_mulo!(i128_overflowing_mul, i128, u128); intrinsics! { + // Ancient Egyptian/Ethiopian/Russian multiplication method + // see https://en.wikipedia.org/wiki/Ancient_Egyptian_multiplication + // + // This is a long-available stock algorithm; e.g. it is documented in + // Knuth's "The Art of Computer Programming" volume 2 (under the section + // "Evaluation of Powers") since at least the 2nd edition (1981). + // + // The main attraction of this method is that it implements (software) + // multiplication atop four simple operations: doubling, halving, checking + // if a value is even/odd, and addition. This is *not* considered to be the + // fastest multiplication method, but it may be amongst the simplest (and + // smallest with respect to code size). + // + // for reference, see also implementation from gcc + // https://raw.githubusercontent.com/gcc-mirror/gcc/master/libgcc/config/epiphany/mulsi3.c + // + // and from LLVM (in relatively readable RISC-V assembly): + // https://github.com/llvm/llvm-project/blob/main/compiler-rt/lib/builtins/riscv/int_mul_impl.inc + #[cfg(any(target_arch = "riscv32", target_arch = "riscv64", target_arch = "m68k"))] + pub extern "C" fn __mulsi3(a: u32, b: u32) -> u32 { + let (mut a, mut b) = (a, b); + let mut r: u32 = 0; + + while a > 0 { + if a & 1 > 0 { + r = r.wrapping_add(b); + } + a >>= 1; + b <<= 1; + } + + r + } + #[maybe_use_optimized_c_shim] #[arm_aeabi_alias = __aeabi_lmul] - #[cfg(any(not(any(target_arch = "riscv32", target_arch = "riscv64")), target_feature = "m"))] pub extern "C" fn __muldi3(a: u64, b: u64) -> u64 { - a.mul(b) + #[cfg(all(any(target_arch = "riscv32", target_arch = "riscv64"), not(target_feature = "m")))] + { + let (mut a, mut b) = (a, b); + let mut r: u64 = 0; + + while a > 0 { + if a & 1 > 0 { + r = r.wrapping_add(b); + } + a >>= 1; + b <<= 1; + } + + r + } + + #[cfg(not(all(any(target_arch = "riscv32", target_arch = "riscv64"), not(target_feature = "m"))))] + { + a.mul(b) + } } pub extern "C" fn __multi3(a: i128, b: i128) -> i128 { @@ -139,4 +191,5 @@ intrinsics! { *oflow = o.into(); mul } + } diff --git a/library/compiler-builtins/compiler-builtins/src/lib.rs b/library/compiler-builtins/compiler-builtins/src/lib.rs index 07960222f20f0..207ec3c19f3ad 100644 --- a/library/compiler-builtins/compiler-builtins/src/lib.rs +++ b/library/compiler-builtins/compiler-builtins/src/lib.rs @@ -70,9 +70,6 @@ pub mod avr; #[cfg(target_arch = "hexagon")] pub mod hexagon; -#[cfg(any(target_arch = "riscv32", target_arch = "riscv64"))] -pub mod riscv; - #[cfg(target_arch = "x86")] pub mod x86; diff --git a/library/compiler-builtins/compiler-builtins/src/riscv.rs b/library/compiler-builtins/compiler-builtins/src/riscv.rs deleted file mode 100644 index bf31255334193..0000000000000 --- a/library/compiler-builtins/compiler-builtins/src/riscv.rs +++ /dev/null @@ -1,50 +0,0 @@ -intrinsics! { - // Ancient Egyptian/Ethiopian/Russian multiplication method - // see https://en.wikipedia.org/wiki/Ancient_Egyptian_multiplication - // - // This is a long-available stock algorithm; e.g. it is documented in - // Knuth's "The Art of Computer Programming" volume 2 (under the section - // "Evaluation of Powers") since at least the 2nd edition (1981). - // - // The main attraction of this method is that it implements (software) - // multiplication atop four simple operations: doubling, halving, checking - // if a value is even/odd, and addition. This is *not* considered to be the - // fastest multiplication method, but it may be amongst the simplest (and - // smallest with respect to code size). - // - // for reference, see also implementation from gcc - // https://raw.githubusercontent.com/gcc-mirror/gcc/master/libgcc/config/epiphany/mulsi3.c - // - // and from LLVM (in relatively readable RISC-V assembly): - // https://github.com/llvm/llvm-project/blob/main/compiler-rt/lib/builtins/riscv/int_mul_impl.inc - pub extern "C" fn __mulsi3(a: u32, b: u32) -> u32 { - let (mut a, mut b) = (a, b); - let mut r: u32 = 0; - - while a > 0 { - if a & 1 > 0 { - r = r.wrapping_add(b); - } - a >>= 1; - b <<= 1; - } - - r - } - - #[cfg(not(target_feature = "m"))] - pub extern "C" fn __muldi3(a: u64, b: u64) -> u64 { - let (mut a, mut b) = (a, b); - let mut r: u64 = 0; - - while a > 0 { - if a & 1 > 0 { - r = r.wrapping_add(b); - } - a >>= 1; - b <<= 1; - } - - r - } -} From d723253b193a0d55fbf7dc2ec3ce4ae3831b6b85 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Sat, 14 Mar 2026 12:38:40 +0000 Subject: [PATCH 005/183] Revert "ci: Pin Miri to the 2026-02-11 nightly" The described issue in the reverted commit is no longer relevant. This reverts commit 870ab266bad7ec0a56abfc433f92e3c2d67a572c. --- library/compiler-builtins/.github/workflows/main.yaml | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/library/compiler-builtins/.github/workflows/main.yaml b/library/compiler-builtins/.github/workflows/main.yaml index e8e600b6c2a3c..af25df5b97fd5 100644 --- a/library/compiler-builtins/.github/workflows/main.yaml +++ b/library/compiler-builtins/.github/workflows/main.yaml @@ -301,9 +301,7 @@ jobs: steps: - uses: actions/checkout@v6 - name: Install Rust (rustup) - # FIXME(ci): not working in the 2026-02-11 nightly - # https://rust-lang.zulipchat.com/#narrow/channel/269128-miri/topic/build-script-build.20contains.20outdated.20or.20invalid.20JSON/with/573426109 - run: rustup update nightly-2026-02-10 --no-self-update && rustup default nightly-2026-02-10 + run: rustup update nightly --no-self-update && rustup default nightly shell: bash - run: rustup component add miri - run: cargo miri setup From 51eea03cf842ae52bbb0390c03323b4189b10bed Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Mon, 16 Mar 2026 14:24:02 -0500 Subject: [PATCH 006/183] ci: Resolve audit issues reported by zizmore Resolve the following lints: * `unpinned-uses`: Pin action versions using `zizmor --fix` * `excessive-permissions`: Add `permissions: {}` to all workflows * `template-injection`: This one wasn't too concerning since `${{ ... }}` was only used for `matrix` and `needs` access, but it is easy enough to resolve by storing in an environment variable. --- .../.github/workflows/main.yaml | 71 +++++++++++-------- .../.github/workflows/publish.yaml | 4 +- .../.github/workflows/rustc-pull.yml | 4 +- 3 files changed, 45 insertions(+), 34 deletions(-) diff --git a/library/compiler-builtins/.github/workflows/main.yaml b/library/compiler-builtins/.github/workflows/main.yaml index af25df5b97fd5..4f33bb1aa6646 100644 --- a/library/compiler-builtins/.github/workflows/main.yaml +++ b/library/compiler-builtins/.github/workflows/main.yaml @@ -1,4 +1,5 @@ name: CI +permissions: {} on: push: { branches: [main] } pull_request: @@ -28,7 +29,7 @@ jobs: extensive_matrix: ${{ steps.script.outputs.extensive_matrix }} may_skip_libm_ci: ${{ steps.script.outputs.may_skip_libm_ci }} steps: - - uses: actions/checkout@v6 + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 with: fetch-depth: 500 - name: Fetch pull request ref @@ -104,6 +105,8 @@ jobs: needs: [calculate_vars] env: BUILD_ONLY: ${{ matrix.build_only }} + JOB_TARGET: ${{ matrix.target }} + JOB_CHANNEL: ${{ matrix.channel }} MAY_SKIP_LIBM_CI: ${{ needs.calculate_vars.outputs.may_skip_libm_ci }} steps: - name: Print $HOME @@ -121,36 +124,38 @@ jobs: if: matrix.os == 'ubuntu-24.04-ppc64le' || matrix.os == 'ubuntu-24.04-s390x' run: sudo apt-get update && sudo apt-get install -y rustup - - uses: actions/checkout@v6 + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 - name: Install Rust (rustup) shell: bash run: | channel="nightly" # Account for channels that have required components (MinGW) - [ -n "${{ matrix.channel }}" ] && channel="${{ matrix.channel }}" + [ -n "$JOB_CHANNEL" ] && channel="$JOB_CHANNEL" rustup update "$channel" --no-self-update rustup default "$channel" - rustup target add "${{ matrix.target }}" + rustup target add "$JOB_TARGET" - - uses: taiki-e/install-action@nextest + - uses: taiki-e/install-action@de6bbd1333b8f331563d54a051e542c7dfef81c3 # v2 + with: + tool: nextest@0.9.130 - - uses: Swatinem/rust-cache@v2 + - uses: Swatinem/rust-cache@e18b497796c12c097a38f9edb9d0641fb99eee32 # v2 with: key: ${{ matrix.target }} - name: Cache Docker layers - uses: actions/cache@v5 + uses: actions/cache@cdf6c1fa76f9f475f3d7449005a359c84ca0f306 # v5 if: matrix.os == 'ubuntu-24.04' with: path: /tmp/.buildx-cache key: ${{ matrix.target }}-buildx-${{ github.sha }} restore-keys: ${{ matrix.target }}-buildx- # Configure buildx to use Docker layer caching - - uses: docker/setup-buildx-action@v4 + - uses: docker/setup-buildx-action@4d04d5d9486b7bd6fa91e7baf45bbb4f8b9deedd # v4 if: matrix.os == 'ubuntu-24.04' - name: Cache compiler-rt id: cache-compiler-rt - uses: actions/cache@v5 + uses: actions/cache@cdf6c1fa76f9f475f3d7449005a359c84ca0f306 # v5 with: path: compiler-rt key: ${{ runner.os }}-compiler-rt-${{ hashFiles('ci/download-compiler-rt.sh') }} @@ -173,12 +178,12 @@ jobs: - name: Run locally if: matrix.os != 'ubuntu-24.04' shell: bash - run: ./ci/run.sh ${{ matrix.target }} + run: ./ci/run.sh "$JOB_TARGET" # Otherwise we use our docker containers to run builds - name: Run in Docker if: matrix.os == 'ubuntu-24.04' - run: ./ci/run-docker.sh ${{ matrix.target }} + run: ./ci/run-docker.sh "$JOB_TARGET" - name: Print test logs if available if: always() @@ -199,14 +204,14 @@ jobs: runs-on: ubuntu-24.04 timeout-minutes: 10 steps: - - uses: actions/checkout@v6 + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 # Unlike rustfmt, stable clippy does not work on code with nightly features. - name: Install nightly `clippy` run: | rustup update nightly --no-self-update rustup default nightly rustup component add clippy - - uses: Swatinem/rust-cache@v2 + - uses: Swatinem/rust-cache@e18b497796c12c097a38f9edb9d0641fb99eee32 # v2 - name: Download musl source run: ./ci/update-musl.sh - run: cargo clippy --workspace --all-targets @@ -216,13 +221,13 @@ jobs: runs-on: ubuntu-24.04 timeout-minutes: 10 steps: - - uses: actions/checkout@v6 + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 - name: Install Rust run: | rustup update nightly --no-self-update rustup default nightly rustup component add rust-src - - uses: Swatinem/rust-cache@v2 + - uses: Swatinem/rust-cache@e18b497796c12c097a38f9edb9d0641fb99eee32 # v2 - run: | # Ensure we can build with custom target.json files (these can interact # poorly with build scripts) @@ -237,13 +242,13 @@ jobs: runs-on: ubuntu-24.04 timeout-minutes: 10 steps: - - uses: actions/checkout@v6 + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 - name: Install Rust run: | rustup update nightly --no-self-update rustup default nightly rustup component add rust-src - - uses: Swatinem/rust-cache@v2 + - uses: Swatinem/rust-cache@e18b497796c12c097a38f9edb9d0641fb99eee32 # v2 - run: | cargo build -p compiler_builtins -p libm \ --target etc/thumbv6-none-eabi.json \ @@ -262,13 +267,17 @@ jobs: - target: aarch64-unknown-linux-gnu os: ubuntu-24.04-arm runs-on: ${{ matrix.os }} + env: + JOB_TARGET: ${{ matrix.target }} steps: - - uses: actions/checkout@v6 - - uses: taiki-e/install-action@cargo-binstall + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 + - uses: taiki-e/install-action@de6bbd1333b8f331563d54a051e542c7dfef81c3 # v2 + with: + tool: cargo-binstall@1.17.7 - name: Set up dependencies run: ./ci/install-bench-deps.sh - - uses: Swatinem/rust-cache@v2 + - uses: Swatinem/rust-cache@e18b497796c12c097a38f9edb9d0641fb99eee32 # v2 with: key: ${{ matrix.target }} - name: Download musl source @@ -278,10 +287,10 @@ jobs: env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} PR_NUMBER: ${{ github.event.pull_request.number }} - run: ./ci/bench-icount.sh ${{ matrix.target }} + run: ./ci/bench-icount.sh "$JOB_TARGET" - name: Upload the benchmark baseline - uses: actions/upload-artifact@v6 + uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6 with: name: ${{ env.BASELINE_NAME }} path: ${{ env.BASELINE_NAME }}.tar.xz @@ -299,13 +308,13 @@ jobs: runs-on: ubuntu-24.04 timeout-minutes: 10 steps: - - uses: actions/checkout@v6 + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 - name: Install Rust (rustup) run: rustup update nightly --no-self-update && rustup default nightly shell: bash - run: rustup component add miri - run: cargo miri setup - - uses: Swatinem/rust-cache@v2 + - uses: Swatinem/rust-cache@e18b497796c12c097a38f9edb9d0641fb99eee32 # v2 - run: ./ci/miri.sh msrv: @@ -315,13 +324,13 @@ jobs: env: RUSTFLAGS: # No need to check warnings on old MSRV, unset `-Dwarnings` steps: - - uses: actions/checkout@v6 + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 - name: Install Rust run: | msrv="$(perl -ne 'print if s/rust-version\s*=\s*"(.*)"/\1/g' libm/Cargo.toml)" echo "MSRV: $msrv" rustup update "$msrv" --no-self-update && rustup default "$msrv" - - uses: Swatinem/rust-cache@v2 + - uses: Swatinem/rust-cache@e18b497796c12c097a38f9edb9d0641fb99eee32 # v2 - run: | # FIXME(msrv): Remove the workspace Cargo.toml so 1.63 cargo doesn't see # `edition = "2024"` and get spooked. @@ -333,7 +342,7 @@ jobs: runs-on: ubuntu-24.04 timeout-minutes: 10 steps: - - uses: actions/checkout@v6 + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 - name: Install nightly `rustfmt` run: rustup set profile minimal && rustup default nightly && rustup component add rustfmt - run: cargo fmt -- --check @@ -356,12 +365,12 @@ jobs: env: TO_TEST: ${{ matrix.to_test }} steps: - - uses: actions/checkout@v6 + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 - name: Install Rust run: | rustup update nightly --no-self-update rustup default nightly - - uses: Swatinem/rust-cache@v2 + - uses: Swatinem/rust-cache@e18b497796c12c097a38f9edb9d0641fb99eee32 # v2 - name: download musl source run: ./ci/update-musl.sh - name: Run extensive tests @@ -387,7 +396,9 @@ jobs: # failed" as success. So we have to do some contortions to ensure the job fails if any of its # dependencies fails. if: always() # make sure this is never "skipped" + env: + NEEDS: ${{ toJson(needs) }} steps: # Manually check the status of all dependencies. `if: failure()` does not work. - name: check if any dependency failed - run: jq --exit-status 'all(.result == "success")' <<< '${{ toJson(needs) }}' + run: jq --exit-status 'all(.result == "success")' <<< "$NEEDS" diff --git a/library/compiler-builtins/.github/workflows/publish.yaml b/library/compiler-builtins/.github/workflows/publish.yaml index b720d765568f9..cb00c2d7dedcd 100644 --- a/library/compiler-builtins/.github/workflows/publish.yaml +++ b/library/compiler-builtins/.github/workflows/publish.yaml @@ -13,12 +13,12 @@ jobs: runs-on: ubuntu-24.04 environment: publish steps: - - uses: actions/checkout@v6 + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 with: fetch-depth: 0 - name: Install Rust (rustup) run: rustup update nightly --no-self-update && rustup default nightly - name: Run release-plz - uses: release-plz/action@v0.5 + uses: release-plz/action@1528104d2ca23787631a1c1f022abb64b34c1e11 # v0.5 env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/library/compiler-builtins/.github/workflows/rustc-pull.yml b/library/compiler-builtins/.github/workflows/rustc-pull.yml index 8e88213332de4..5fc63984b6bc1 100644 --- a/library/compiler-builtins/.github/workflows/rustc-pull.yml +++ b/library/compiler-builtins/.github/workflows/rustc-pull.yml @@ -1,6 +1,6 @@ # Perform a subtree sync (pull) using the josh-sync tool once every few days (or on demand). name: rustc-pull - +permissions: {} on: workflow_dispatch: schedule: @@ -13,7 +13,7 @@ env: jobs: pull: if: github.repository == 'rust-lang/compiler-builtins' - uses: rust-lang/josh-sync/.github/workflows/rustc-pull.yml@main + uses: rust-lang/josh-sync/.github/workflows/rustc-pull.yml@a097aeb82f49801051560482307ceaca7e58bf97 # main with: github-app-id: ${{ vars.APP_CLIENT_ID }} # https://rust-lang.zulipchat.com/#narrow/channel/219381-t-libs/topic/compiler-builtins.20subtree.20sync.20automation/with/528482375 From 549b6d708d76af8995f82462b90eca74b9f16a14 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Tue, 17 Mar 2026 10:25:37 -0400 Subject: [PATCH 007/183] ci: Add configuration for renovatebot (#1114) Based on the configuration for bors [1]. [1]: https://github.com/rust-lang/bors/blob/d89bfc24e8e7add3b03af3ab7307cd3b2a1af879/.github/renovate.json5 --- .../compiler-builtins/.github/renovate.json5 | 37 +++++++++++++++++++ 1 file changed, 37 insertions(+) create mode 100644 library/compiler-builtins/.github/renovate.json5 diff --git a/library/compiler-builtins/.github/renovate.json5 b/library/compiler-builtins/.github/renovate.json5 new file mode 100644 index 0000000000000..1937b1c6d34a8 --- /dev/null +++ b/library/compiler-builtins/.github/renovate.json5 @@ -0,0 +1,37 @@ +{ + $schema: "https://docs.renovatebot.com/renovate-schema.json", + extends: [ + "config:recommended", + ":maintainLockFilesMonthly", + "helpers:pinGitHubActionDigestsToSemver" + ], + packageRules: [ + { + matchCategories: [ + "rust" + ], + updateTypes: [ + "patch" + ], + // Disable patch updates for single dependencies because patches + // are updated periodically with lockfile maintainance. + enabled: false, + }, + { + matchManagers: [ + "github-actions" + ], + // Every month + schedule: "* 0 1 * *", + groupName: "Github Actions", + } + ], + // Receive any update that fixes security vulnerabilities. + // We need this because we disabled "patch" updates for Rust. + // Note: You need to enable "Dependabot alerts" in "Code security" GitHub + // Settings to receive security updates. + // See https://docs.renovatebot.com/configuration-options/#vulnerabilityalerts + vulnerabilityAlerts: { + enabled: true, + }, +} From 741b5e93cdb269807d28ba68e173eaeab2d214a7 Mon Sep 17 00:00:00 2001 From: Bo YU Date: Sun, 15 Mar 2026 15:23:12 +0000 Subject: [PATCH 008/183] Add zizmor to check Github Actions (static analysis) --- .../compiler-builtins/.github/workflows/main.yaml | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/library/compiler-builtins/.github/workflows/main.yaml b/library/compiler-builtins/.github/workflows/main.yaml index 4f33bb1aa6646..c0ce94e1eeecd 100644 --- a/library/compiler-builtins/.github/workflows/main.yaml +++ b/library/compiler-builtins/.github/workflows/main.yaml @@ -216,6 +216,19 @@ jobs: run: ./ci/update-musl.sh - run: cargo clippy --workspace --all-targets + zizmor: + name: Zizmor (Static analysis for GitHub Actions) + runs-on: ubuntu-24.04 + permissions: + security-events: write + timeout-minutes: 10 + steps: + - name: Checkout repository + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + + - name: Run zizmor + uses: zizmorcore/zizmor-action@71321a20a9ded102f6e9ce5718a2fcec2c4f70d8 # v0.5.2 + build-custom: name: Build custom target runs-on: ubuntu-24.04 @@ -390,6 +403,7 @@ jobs: - msrv - rustfmt - test + - zizmor runs-on: ubuntu-24.04 timeout-minutes: 10 # GitHub branch protection is exceedingly silly and treats "jobs skipped because a dependency From 41a6f3e24e21ca9693febff7397751806ece36bf Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Tue, 17 Mar 2026 10:47:19 -0400 Subject: [PATCH 009/183] ci: Resolve audit issues reported by zizmore Resolve two cases of `ref-version-mismatch` and various `artipacked` instances. --- .../.github/workflows/main.yaml | 22 +++++++++++++------ .../.github/workflows/publish.yaml | 1 + 2 files changed, 16 insertions(+), 7 deletions(-) diff --git a/library/compiler-builtins/.github/workflows/main.yaml b/library/compiler-builtins/.github/workflows/main.yaml index c0ce94e1eeecd..6b444cad2507a 100644 --- a/library/compiler-builtins/.github/workflows/main.yaml +++ b/library/compiler-builtins/.github/workflows/main.yaml @@ -31,6 +31,7 @@ jobs: steps: - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 with: + persist-credentials: false fetch-depth: 500 - name: Fetch pull request ref run: git fetch origin "$GITHUB_REF:$GITHUB_REF" @@ -125,6 +126,7 @@ jobs: run: sudo apt-get update && sudo apt-get install -y rustup - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 + with: { persist-credentials: false } - name: Install Rust (rustup) shell: bash run: | @@ -135,7 +137,7 @@ jobs: rustup default "$channel" rustup target add "$JOB_TARGET" - - uses: taiki-e/install-action@de6bbd1333b8f331563d54a051e542c7dfef81c3 # v2 + - uses: taiki-e/install-action@de6bbd1333b8f331563d54a051e542c7dfef81c3 # v2.68.34 with: tool: nextest@0.9.130 @@ -205,6 +207,7 @@ jobs: timeout-minutes: 10 steps: - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 + with: { persist-credentials: false } # Unlike rustfmt, stable clippy does not work on code with nightly features. - name: Install nightly `clippy` run: | @@ -223,11 +226,9 @@ jobs: security-events: write timeout-minutes: 10 steps: - - name: Checkout repository - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 - - - name: Run zizmor - uses: zizmorcore/zizmor-action@71321a20a9ded102f6e9ce5718a2fcec2c4f70d8 # v0.5.2 + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + with: { persist-credentials: false } + - uses: zizmorcore/zizmor-action@71321a20a9ded102f6e9ce5718a2fcec2c4f70d8 # v0.5.2 build-custom: name: Build custom target @@ -235,6 +236,7 @@ jobs: timeout-minutes: 10 steps: - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 + with: { persist-credentials: false } - name: Install Rust run: | rustup update nightly --no-self-update @@ -256,6 +258,7 @@ jobs: timeout-minutes: 10 steps: - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 + with: { persist-credentials: false } - name: Install Rust run: | rustup update nightly --no-self-update @@ -284,7 +287,8 @@ jobs: JOB_TARGET: ${{ matrix.target }} steps: - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 - - uses: taiki-e/install-action@de6bbd1333b8f331563d54a051e542c7dfef81c3 # v2 + with: { persist-credentials: false } + - uses: taiki-e/install-action@de6bbd1333b8f331563d54a051e542c7dfef81c3 # v2.68.34 with: tool: cargo-binstall@1.17.7 @@ -322,6 +326,7 @@ jobs: timeout-minutes: 10 steps: - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 + with: { persist-credentials: false } - name: Install Rust (rustup) run: rustup update nightly --no-self-update && rustup default nightly shell: bash @@ -338,6 +343,7 @@ jobs: RUSTFLAGS: # No need to check warnings on old MSRV, unset `-Dwarnings` steps: - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 + with: { persist-credentials: false } - name: Install Rust run: | msrv="$(perl -ne 'print if s/rust-version\s*=\s*"(.*)"/\1/g' libm/Cargo.toml)" @@ -356,6 +362,7 @@ jobs: timeout-minutes: 10 steps: - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 + with: { persist-credentials: false } - name: Install nightly `rustfmt` run: rustup set profile minimal && rustup default nightly && rustup component add rustfmt - run: cargo fmt -- --check @@ -379,6 +386,7 @@ jobs: TO_TEST: ${{ matrix.to_test }} steps: - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 + with: { persist-credentials: false } - name: Install Rust run: | rustup update nightly --no-self-update diff --git a/library/compiler-builtins/.github/workflows/publish.yaml b/library/compiler-builtins/.github/workflows/publish.yaml index cb00c2d7dedcd..738de77305ec8 100644 --- a/library/compiler-builtins/.github/workflows/publish.yaml +++ b/library/compiler-builtins/.github/workflows/publish.yaml @@ -15,6 +15,7 @@ jobs: steps: - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 with: + persist-credentials: false fetch-depth: 0 - name: Install Rust (rustup) run: rustup update nightly --no-self-update && rustup default nightly From d552a7cd70412bf6e944d14ce175018b9c04ba48 Mon Sep 17 00:00:00 2001 From: Juho Kahala <57393910+quaternic@users.noreply.github.com> Date: Fri, 20 Mar 2026 17:54:33 +0200 Subject: [PATCH 010/183] libm: fix test for overflow in u256::shr --- .../compiler-builtins/libm/src/math/support/big/tests.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/library/compiler-builtins/libm/src/math/support/big/tests.rs b/library/compiler-builtins/libm/src/math/support/big/tests.rs index 2eafed50a2757..8750241073477 100644 --- a/library/compiler-builtins/libm/src/math/support/big/tests.rs +++ b/library/compiler-builtins/libm/src/math/support/big/tests.rs @@ -269,10 +269,10 @@ fn shr_u256_overflow() { #[test] #[cfg(not(debug_assertions))] fn shr_u256_overflow() { - // No panic without debug assertions - assert_eq!(u256::MAX >> 256, u256::ZERO); - assert_eq!(u256::MAX >> 257, u256::ZERO); - assert_eq!(u256::MAX >> u32::MAX, u256::ZERO); + // Without debug assertions, the shift amount is wrapped + assert_eq!(u256::MAX >> 256, u256::MAX); + assert_eq!(u256::MAX >> 257, u256::MAX >> 1); + assert_eq!(u256::MAX >> u32::MAX, u256::ONE); } #[test] From 74955ac95c06245e8a0f6d703fbf03724e68b42f Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Sun, 22 Mar 2026 15:38:48 -0500 Subject: [PATCH 011/183] libm: Remove `hexu` in favor of formatting traits on `u256` Use the same trick as with other formatting implementations, which makes it possible to get rid of the awkward `-> String` functions. --- .../compiler-builtins/libm-test/tests/u256.rs | 42 ++++++------------- .../libm/src/math/support/big.rs | 39 +++++++++++++++-- .../libm/src/math/support/big/tests.rs | 23 +++------- .../libm/src/math/support/hex_float.rs | 6 +-- 4 files changed, 57 insertions(+), 53 deletions(-) diff --git a/library/compiler-builtins/libm-test/tests/u256.rs b/library/compiler-builtins/libm-test/tests/u256.rs index e697945f47971..dc8e90acb2d29 100644 --- a/library/compiler-builtins/libm-test/tests/u256.rs +++ b/library/compiler-builtins/libm-test/tests/u256.rs @@ -19,11 +19,6 @@ use rug::ops::NotAssign; static BIGINT_U256_MAX: LazyLock = LazyLock::new(|| BigInt::from_digits(&[u128::MAX, u128::MAX], Order::Lsf)); -/// Copied from the test module. -fn hexu(v: u256) -> String { - format!("0x{:032x}{:032x}", v.hi, v.lo) -} - fn random_u256(rng: &mut ChaCha8Rng) -> u256 { let lo: u128 = rng.random(); let hi: u128 = rng.random(); @@ -46,25 +41,15 @@ fn from_bigint(bx: &mut BigInt) -> u256 { } } -fn check_one( - x: impl FnOnce() -> String, - y: impl FnOnce() -> Option, - actual: u256, - expected: &mut BigInt, -) { +fn check_one(msg: impl Fn() -> String, actual: u256, expected: &mut BigInt) { let expected = from_bigint(expected); if actual != expected { - let xmsg = x(); - let ymsg = y().map(|y| format!("y: {y}\n")).unwrap_or_default(); panic!( - "Results do not match\n\ - input: {xmsg}\n\ - {ymsg}\ - actual: {}\n\ - expected: {}\ + "Test failure: {}\n\ + actual: {actual:#x}\n\ + expected: {expected:#x}\ ", - hexu(actual), - hexu(expected), + msg() ) } } @@ -82,7 +67,7 @@ fn mp_u256_bitor() { assign_bigint(&mut by, y); let actual = x | y; bx |= &by; - check_one(|| hexu(x), || Some(hexu(y)), actual, &mut bx); + check_one(|| format!("{x:#x} ^ {y:#x}"), actual, &mut bx); } } @@ -96,7 +81,7 @@ fn mp_u256_not() { assign_bigint(&mut bx, x); let actual = !x; bx.not_assign(); - check_one(|| hexu(x), || None, actual, &mut bx); + check_one(|| format!("!{x:#x}"), actual, &mut bx); } } @@ -119,7 +104,7 @@ fn mp_u256_add() { y - (u256::MAX - x) - 1_u128.widen() }; bx += &by; - check_one(|| hexu(x), || Some(hexu(y)), actual, &mut bx); + check_one(|| format!("{x:#x} + {y:#x}"), actual, &mut bx); } } @@ -140,7 +125,7 @@ fn mp_u256_sub() { let actual = if x >= y { x - y } else { y - x }; bx -= &by; bx.abs_mut(); - check_one(|| hexu(x), || Some(hexu(y)), actual, &mut bx); + check_one(|| format!("{x:#x} - {y:#x}"), actual, &mut bx); } } @@ -155,7 +140,7 @@ fn mp_u256_shl() { assign_bigint(&mut bx, x); let actual = x << shift; bx <<= shift; - check_one(|| hexu(x), || Some(shift.to_string()), actual, &mut bx); + check_one(|| format!("{x:#x} << {shift}"), actual, &mut bx); } } @@ -170,12 +155,12 @@ fn mp_u256_shr() { assign_bigint(&mut bx, x); let actual = x >> shift; bx >>= shift; - check_one(|| hexu(x), || Some(shift.to_string()), actual, &mut bx); + check_one(|| format!("{x:#x} >> {shift}"), actual, &mut bx); } } #[test] -fn mp_u256_widen_mul() { +fn mp_u256_u128_widen_mul() { let mut rng = ChaCha8Rng::from_seed(*SEED); let mut bx = BigInt::new(); let mut by = BigInt::new(); @@ -188,8 +173,7 @@ fn mp_u256_widen_mul() { let actual = x.widen_mul(y); bx *= &by; check_one( - || format!("{x:#034x}"), - || Some(format!("{y:#034x}")), + || format!("{x:#034x}.widen_mul({y:#034x})"), actual, &mut bx, ); diff --git a/library/compiler-builtins/libm/src/math/support/big.rs b/library/compiler-builtins/libm/src/math/support/big.rs index b7f1285424956..24e3fbf11461c 100644 --- a/library/compiler-builtins/libm/src/math/support/big.rs +++ b/library/compiler-builtins/libm/src/math/support/big.rs @@ -3,7 +3,7 @@ #[cfg(test)] mod tests; -use core::ops; +use core::{fmt, ops}; use super::{DInt, HInt, Int, MinInt}; @@ -11,7 +11,7 @@ const U128_LO_MASK: u128 = u64::MAX as u128; /// A 256-bit unsigned integer represented as two 128-bit native-endian limbs. #[allow(non_camel_case_types)] -#[derive(Clone, Copy, Debug, PartialEq, PartialOrd, Eq, Ord)] +#[derive(Clone, Copy, PartialEq, PartialOrd, Eq, Ord)] pub struct u256 { pub hi: u128, pub lo: u128, @@ -35,7 +35,7 @@ impl u256 { /// A 256-bit signed integer represented as two 128-bit native-endian limbs. #[allow(non_camel_case_types)] -#[derive(Clone, Copy, Debug, PartialEq, PartialOrd, Eq, Ord)] +#[derive(Clone, Copy, PartialEq, PartialOrd, Eq, Ord)] pub struct i256 { pub hi: i128, pub lo: u128, @@ -43,7 +43,6 @@ pub struct i256 { impl i256 { /// Reinterpret as an unsigned integer - #[cfg(any(test, feature = "unstable-public-internals"))] pub fn unsigned(self) -> u256 { u256 { lo: self.lo, @@ -280,3 +279,35 @@ impl DInt for i256 { self.hi } } + +impl fmt::Debug for u256 { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + fmt::LowerHex::fmt(self, f) + } +} + +impl fmt::Debug for i256 { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + fmt::LowerHex::fmt(&self.unsigned(), f) + } +} + +impl fmt::LowerHex for u256 { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + cfg_if! { + if #[cfg(feature = "compiler-builtins")] { + let _ = f; + unimplemented!() + } else { + let pfx= if f.alternate() { "0x"} else {""}; + write!(f, "{pfx}{:032x}{:032x}", self.hi, self.lo) + } + } + } +} + +impl fmt::LowerHex for i256 { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + fmt::LowerHex::fmt(&self.unsigned(), f) + } +} diff --git a/library/compiler-builtins/libm/src/math/support/big/tests.rs b/library/compiler-builtins/libm/src/math/support/big/tests.rs index 8750241073477..133e3739314d0 100644 --- a/library/compiler-builtins/libm/src/math/support/big/tests.rs +++ b/library/compiler-builtins/libm/src/math/support/big/tests.rs @@ -1,17 +1,11 @@ extern crate std; -use std::string::String; -use std::{eprintln, format}; +use std::eprintln; use super::{HInt, MinInt, i256, u256}; use crate::support::{Int as _, NarrowingDiv}; const LOHI_SPLIT: u128 = 0xaaaaaaaaaaaaaaaaffffffffffffffff; -/// Print a `u256` as hex since we can't add format implementations -fn hexu(v: u256) -> String { - format!("0x{:032x}{:032x}", v.hi, v.lo) -} - #[test] fn widen_u128() { assert_eq!( @@ -81,11 +75,9 @@ fn widen_mul_u128() { eprintln!( "\ FAILURE ({i}): {a:#034x} * {b:#034x}\n\ - expected: {}\n\ - got: {}\ + expected: {expected:#x}\n\ + actual: {actual:#x}\ ", - hexu(expected), - hexu(actual) ); }; @@ -121,13 +113,10 @@ fn shr_u256() { has_errors = true; eprintln!( "\ - FAILURE: {} >> {b}\n\ - expected: {}\n\ - actual: {}\ + FAILURE: {a:#x} >> {b}\n\ + expected: {expected:#x}\n\ + actual: {actual:#x}\ ", - hexu(a), - hexu(expected), - hexu(actual), ); }; diff --git a/library/compiler-builtins/libm/src/math/support/hex_float.rs b/library/compiler-builtins/libm/src/math/support/hex_float.rs index 5be0d3159de3b..6d75e760fbb0a 100644 --- a/library/compiler-builtins/libm/src/math/support/hex_float.rs +++ b/library/compiler-builtins/libm/src/math/support/hex_float.rs @@ -326,9 +326,9 @@ const fn hex_digit(c: u8) -> Option { #[cfg(any(test, feature = "unstable-public-internals"))] mod hex_fmt { - use core::fmt; + use core::fmt::{self, LowerHex}; - use crate::support::{Float, Int}; + use crate::support::{Float, MinInt}; /// Format a floating point number as its IEEE hex (`%a`) representation. pub struct Hexf(pub F); @@ -461,7 +461,7 @@ mod hex_fmt { pub struct Hexi(pub F); - impl fmt::LowerHex for Hexi { + impl fmt::LowerHex for Hexi { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { cfg_if! { if #[cfg(feature = "compiler-builtins")] { From 43b30e82bc6331189ced30fe5fab97f2dadde596 Mon Sep 17 00:00:00 2001 From: Bo YU Date: Thu, 19 Mar 2026 23:11:26 +0000 Subject: [PATCH 012/183] ci: update nextest to 0.9.131 with install-action --- library/compiler-builtins/.github/workflows/main.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/library/compiler-builtins/.github/workflows/main.yaml b/library/compiler-builtins/.github/workflows/main.yaml index 6b444cad2507a..f9215cb00baa7 100644 --- a/library/compiler-builtins/.github/workflows/main.yaml +++ b/library/compiler-builtins/.github/workflows/main.yaml @@ -137,9 +137,9 @@ jobs: rustup default "$channel" rustup target add "$JOB_TARGET" - - uses: taiki-e/install-action@de6bbd1333b8f331563d54a051e542c7dfef81c3 # v2.68.34 + - uses: taiki-e/install-action@42721ded7ddc3cd90f687527e8602066e4e1ff3a # v2.69.2 with: - tool: nextest@0.9.130 + tool: nextest@0.9.131 - uses: Swatinem/rust-cache@e18b497796c12c097a38f9edb9d0641fb99eee32 # v2 with: From ca309a4015f20f61602e3b070489817e91f396db Mon Sep 17 00:00:00 2001 From: vimer Date: Tue, 24 Mar 2026 00:54:58 +0800 Subject: [PATCH 013/183] ci: Test on riscv64 using a self-hosted runner Closes: https://github.com/rust-lang/compiler-builtins/issues/1054 --- library/compiler-builtins/.github/workflows/main.yaml | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/library/compiler-builtins/.github/workflows/main.yaml b/library/compiler-builtins/.github/workflows/main.yaml index f9215cb00baa7..e4bb833526caf 100644 --- a/library/compiler-builtins/.github/workflows/main.yaml +++ b/library/compiler-builtins/.github/workflows/main.yaml @@ -44,6 +44,9 @@ jobs: test: name: Build and test timeout-minutes: 60 + # NOTE: self-hosted riscv64 runners are experimental and may be flaky. + # Do not block CI on failures from this platform for now. + continue-on-error: ${{ contains(matrix.os, 'self-hosted') }} strategy: fail-fast: false matrix: @@ -74,6 +77,8 @@ jobs: os: ubuntu-24.04 - target: powerpc64le-unknown-linux-gnu os: ubuntu-24.04-ppc64le + - target: riscv64gc-unknown-linux-gnu + os: ["self-hosted", "linux", "riscv64"] - target: riscv64gc-unknown-linux-gnu os: ubuntu-24.04 - target: s390x-unknown-linux-gnu @@ -173,7 +178,7 @@ jobs: shell: bash - name: Verify API list - if: matrix.os == 'ubuntu-24.04' + if: matrix.os == 'ubuntu-24.04' || contains(matrix.os, 'self-hosted') run: python3 etc/update-api-list.py --check # Non-linux tests just use our raw script From d3e8724f2524488c5baf51d87797a79ed68489c3 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Sun, 22 Mar 2026 22:14:30 -0500 Subject: [PATCH 014/183] test: Use the libm testing infra to test compiler-builtins Add wrappers for compiler-builtins that closer match the libm interfaces, and add basic compiler-builtins float arithmetic to the set of tested functions. This means we now get tests against MPFR, better edge case coverage, extensive testing, and benchmarks for the following functions: * `__add[hsdt]f3` * `__sub[hsdt]f3` * `__mul[hsdt]f3` * `__div[sdt]f3` * `__powi[sdt]f2` Functions from compiler-builtins have not yet been tied in with `update-api-list.py` and the CI tooling that reads it, that will need to be updated in a follow up. --- library/compiler-builtins/Cargo.lock | 1 + library/compiler-builtins/ci/ci-util.py | 4 + .../crates/libm-macros/src/lib.rs | 42 +++- .../crates/libm-macros/src/parse.rs | 15 +- .../crates/libm-macros/src/shared.rs | 186 ++++++++++++++---- .../crates/libm-macros/tests/basic.rs | 11 +- .../compiler-builtins/crates/util/src/main.rs | 10 +- .../compiler-builtins/etc/update-api-list.py | 12 +- .../compiler-builtins/libm-test/Cargo.toml | 1 + .../libm-test/benches/icount.rs | 18 ++ .../libm-test/benches/random.rs | 3 +- .../libm-test/src/builtins_wrapper.rs | 51 +++++ .../compiler-builtins/libm-test/src/domain.rs | 8 + .../libm-test/src/generate/case_list.rs | 84 ++++++++ .../compiler-builtins/libm-test/src/lib.rs | 1 + .../libm-test/src/mpfloat.rs | 107 +++++++++- library/compiler-builtins/libm-test/src/op.rs | 8 +- .../libm-test/src/precision.rs | 7 + .../libm-test/tests/check_coverage.rs | 9 +- .../libm-test/tests/compare_built_musl.rs | 1 + 20 files changed, 515 insertions(+), 64 deletions(-) create mode 100644 library/compiler-builtins/libm-test/src/builtins_wrapper.rs diff --git a/library/compiler-builtins/Cargo.lock b/library/compiler-builtins/Cargo.lock index 7a3e9a38430b6..220e7048512b5 100644 --- a/library/compiler-builtins/Cargo.lock +++ b/library/compiler-builtins/Cargo.lock @@ -664,6 +664,7 @@ name = "libm-test" version = "0.1.0" dependencies = [ "anyhow", + "compiler_builtins", "criterion", "getrandom", "gmp-mpfr-sys", diff --git a/library/compiler-builtins/ci/ci-util.py b/library/compiler-builtins/ci/ci-util.py index 392f83c219e7a..f359c59797448 100755 --- a/library/compiler-builtins/ci/ci-util.py +++ b/library/compiler-builtins/ci/ci-util.py @@ -361,6 +361,10 @@ def base_name(name: str) -> tuple[str, str]: return (name.rstrip("f"), "f32") elif name.endswith("f16"): return (name.rstrip("f16"), "f16") + elif name.endswith("f32"): + return (name.rstrip("f32"), "f32") + elif name.endswith("f64"): + return (name.rstrip("f64"), "f64") elif name.endswith("f128"): return (name.rstrip("f128"), "f128") diff --git a/library/compiler-builtins/crates/libm-macros/src/lib.rs b/library/compiler-builtins/crates/libm-macros/src/lib.rs index 7efa1488f570e..0bb32589795b4 100644 --- a/library/compiler-builtins/crates/libm-macros/src/lib.rs +++ b/library/compiler-builtins/crates/libm-macros/src/lib.rs @@ -9,10 +9,10 @@ use quote::{ToTokens, quote}; pub(crate) use shared::{ALL_OPERATIONS, FloatTy, MathOpInfo, Ty}; use syn::spanned::Spanned; use syn::visit_mut::VisitMut; -use syn::{Ident, ItemEnum}; +use syn::{Ident, ItemEnum, PathArguments, PathSegment}; const KNOWN_TYPES: &[&str] = &[ - "FTy", "CFn", "CArgs", "CRet", "RustFn", "RustArgs", "RustRet", "public", + "FTy", "CFn", "CArgs", "CRet", "RustFn", "RustArgs", "RustRet", "path", ]; /// Populate an enum with a variant representing function. Names are in upper camel case. @@ -80,8 +80,8 @@ pub fn base_name_enum(attributes: pm::TokenStream, tokens: pm::TokenStream) -> p /// RustArgs: $RustArgs:ty, /// // The Rust version's return type (e.g. `(f32, f32)`) /// RustRet: $RustRet:ty, -/// // True if this is part of `libm`'s public API -/// public: $public:expr, +/// // Path to the function, e.g. `libm::fma` or `crate::builtins_wrapper::addf32`. +/// path: $path:path, /// // Attributes for the current function, if any /// attrs: [$($attr:meta),*], /// // Extra tokens passed directly (if any) @@ -160,6 +160,18 @@ fn validate(input: &mut StructuredInput) -> syn::Result map.insert(Ident::new(op.name, key.span()), val.clone()); } } + + if let Some(k) = map.keys().find(|key| *key == "ALL_BUILTINS") { + let key = k.clone(); + let val = map.remove(&key).unwrap(); + + for op in ALL_OPERATIONS + .iter() + .filter(|op| op.scope.defined_in_compiler_builtins()) + { + map.insert(Ident::new(op.name, key.span()), val.clone()); + } + } } // Collect lists of all functions that are provied as macro inputs in various fields (only, @@ -225,6 +237,10 @@ fn validate(input: &mut StructuredInput) -> syn::Result continue; } + if input.skip_builtins && func.scope.defined_in_compiler_builtins() { + continue; + } + // Run everything else fn_list.push(func); } @@ -361,7 +377,17 @@ fn expand(input: StructuredInput, fn_list: &[&MathOpInfo]) -> syn::Result syn::Result quote! { RustFn: fn( #(#rust_args),* ,) -> ( #(#rust_ret),* ), }, "RustArgs" => quote! { RustArgs: ( #(#rust_args),* ,), }, "RustRet" => quote! { RustRet: ( #(#rust_ret),* ), }, - "public" => quote! { public: #public, }, - _ => unreachable!("checked in validation"), + "path" => quote! { path: #path, }, + _ => unreachable!("fields should be checked in validation"), }; ty_fields.push(field); } @@ -463,6 +489,8 @@ fn base_name(name: &str) -> &str { None => name .strip_suffix("f") .or_else(|| name.strip_suffix("f16")) + .or_else(|| name.strip_suffix("f32")) + .or_else(|| name.strip_suffix("f64")) .or_else(|| name.strip_suffix("f128")) .unwrap_or(name), } diff --git a/library/compiler-builtins/crates/libm-macros/src/parse.rs b/library/compiler-builtins/crates/libm-macros/src/parse.rs index 4876f3ef7263a..97067b876bda6 100644 --- a/library/compiler-builtins/crates/libm-macros/src/parse.rs +++ b/library/compiler-builtins/crates/libm-macros/src/parse.rs @@ -50,9 +50,13 @@ pub struct StructuredInput { pub emit_types: Vec, /// Skip these functions pub skip: Vec, - /// If true, omit f16 and f128 functions that aren't present in other libraries. + /// If true, omit f16 and f128 functions that may not be present in libraries we test + /// against (e.g. musl). pub skip_f16_f128: bool, - /// Invoke only for these functions + /// If true, omit functions that are defined in `compiler-builtins` and are not present + /// in libraries we test against (e.g. musl). + pub skip_builtins: bool, + /// Invoke only for the functions listed here. pub only: Option>, /// Attributes that get applied to specific functions pub attributes: Option>, @@ -73,6 +77,7 @@ impl StructuredInput { let emit_types_expr = expect_field(&mut map, "emit_types").ok(); let skip_expr = expect_field(&mut map, "skip").ok(); let skip_f16_f128 = expect_field(&mut map, "skip_f16_f128").ok(); + let skip_builtins = expect_field(&mut map, "skip_builtins").ok(); let only_expr = expect_field(&mut map, "only").ok(); let attr_expr = expect_field(&mut map, "attributes").ok(); let extra = expect_field(&mut map, "extra").ok(); @@ -101,6 +106,11 @@ impl StructuredInput { None => false, }; + let skip_builtins = match skip_builtins { + Some(expr) => expect_litbool(expr)?.value, + None => false, + }; + let only_span = only_expr.as_ref().map(|expr| expr.span()); let only = match only_expr { Some(expr) => Some(Parser::parse2(parse_ident_array, expr.into_token_stream())?), @@ -131,6 +141,7 @@ impl StructuredInput { emit_types, skip, skip_f16_f128, + skip_builtins, only, only_span, attributes, diff --git a/library/compiler-builtins/crates/libm-macros/src/shared.rs b/library/compiler-builtins/crates/libm-macros/src/shared.rs index ee1feed7c35eb..309504890fe58 100644 --- a/library/compiler-builtins/crates/libm-macros/src/shared.rs +++ b/library/compiler-builtins/crates/libm-macros/src/shared.rs @@ -1,5 +1,6 @@ /* List of all functions that is shared between `libm-macros` and `libm-test`. */ +use std::collections::HashSet; use std::fmt; use std::sync::LazyLock; @@ -8,12 +9,114 @@ struct NestedOp { rust_sig: Signature, c_sig: Option, fn_list: &'static [&'static str], - public: bool, + scope: OpScope, +} + +/// Indicate where a function is defined and whether it is public or private. +#[derive(Clone, Copy, Debug)] +pub enum OpScope { + /// Part of `libm`'s public API. + LibmPublic, + /// Functions internal to `libm`, e.g. `rem_pio2`. + #[allow(dead_code)] + LibmPrivate, + /// Functions part of the public API for `compiler-builtins`. + BuiltinsPublic, +} + +impl OpScope { + /// Where we should look for functions of this scope. + pub const fn path_root(self) -> &'static str { + match self { + OpScope::LibmPublic => "libm", + OpScope::LibmPrivate => todo!(), + OpScope::BuiltinsPublic => "crate::builtins_wrapper", + } + } + + pub fn defined_in_compiler_builtins(self) -> bool { + match self { + OpScope::LibmPublic | OpScope::LibmPrivate => false, + OpScope::BuiltinsPublic => true, + } + } } /// We need a flat list to work with most of the time, but define things as a more convenient /// nested list. const ALL_OPERATIONS_NESTED: &[NestedOp] = &[ + /* compiler-builtins operations */ + NestedOp { + float_ty: FloatTy::F16, + rust_sig: Signature { + args: &[Ty::F16, Ty::F16], + returns: &[Ty::F16], + }, + c_sig: None, + fn_list: &["addf16", "mulf16", "subf16"], + scope: OpScope::BuiltinsPublic, + }, + NestedOp { + float_ty: FloatTy::F32, + rust_sig: Signature { + args: &[Ty::F32, Ty::F32], + returns: &[Ty::F32], + }, + c_sig: None, + fn_list: &["addf32", "divf32", "mulf32", "subf32"], + scope: OpScope::BuiltinsPublic, + }, + NestedOp { + float_ty: FloatTy::F64, + rust_sig: Signature { + args: &[Ty::F64, Ty::F64], + returns: &[Ty::F64], + }, + c_sig: None, + fn_list: &["addf64", "divf64", "mulf64", "subf64"], + scope: OpScope::BuiltinsPublic, + }, + NestedOp { + float_ty: FloatTy::F128, + rust_sig: Signature { + args: &[Ty::F128, Ty::F128], + returns: &[Ty::F128], + }, + c_sig: None, + fn_list: &["addf128", "divf128", "mulf128", "subf128"], + scope: OpScope::BuiltinsPublic, + }, + NestedOp { + float_ty: FloatTy::F32, + rust_sig: Signature { + args: &[Ty::F32, Ty::I32], + returns: &[Ty::F32], + }, + c_sig: None, + fn_list: &["powif32"], + scope: OpScope::BuiltinsPublic, + }, + NestedOp { + float_ty: FloatTy::F64, + rust_sig: Signature { + args: &[Ty::F64, Ty::I32], + returns: &[Ty::F64], + }, + c_sig: None, + fn_list: &["powif64"], + scope: OpScope::BuiltinsPublic, + }, + NestedOp { + float_ty: FloatTy::F128, + rust_sig: Signature { + args: &[Ty::F128, Ty::I32], + returns: &[Ty::F128], + }, + c_sig: None, + fn_list: &["powif128"], + scope: OpScope::BuiltinsPublic, + }, + /* libm operations */ NestedOp { // `fn(f16) -> f16` float_ty: FloatTy::F16, @@ -32,7 +135,7 @@ const ALL_OPERATIONS_NESTED: &[NestedOp] = &[ "sqrtf16", "truncf16", ], - public: true, + scope: OpScope::LibmPublic, }, NestedOp { // `fn(f32) -> f32` @@ -81,7 +184,7 @@ const ALL_OPERATIONS_NESTED: &[NestedOp] = &[ "y0f", "y1f", ], - public: true, + scope: OpScope::LibmPublic, }, NestedOp { // `(f64) -> f64` @@ -130,7 +233,7 @@ const ALL_OPERATIONS_NESTED: &[NestedOp] = &[ "y0", "y1", ], - public: true, + scope: OpScope::LibmPublic, }, NestedOp { // `fn(f128) -> f128` @@ -150,7 +253,7 @@ const ALL_OPERATIONS_NESTED: &[NestedOp] = &[ "sqrtf128", "truncf128", ], - public: true, + scope: OpScope::LibmPublic, }, NestedOp { // `(f16, f16) -> f16` @@ -171,7 +274,7 @@ const ALL_OPERATIONS_NESTED: &[NestedOp] = &[ "fminimumf16", "fmodf16", ], - public: true, + scope: OpScope::LibmPublic, }, NestedOp { // `(f32, f32) -> f32` @@ -197,7 +300,7 @@ const ALL_OPERATIONS_NESTED: &[NestedOp] = &[ "powf", "remainderf", ], - public: true, + scope: OpScope::LibmPublic, }, NestedOp { // `(f64, f64) -> f64` @@ -223,7 +326,7 @@ const ALL_OPERATIONS_NESTED: &[NestedOp] = &[ "pow", "remainder", ], - public: true, + scope: OpScope::LibmPublic, }, NestedOp { // `(f128, f128) -> f128` @@ -244,7 +347,7 @@ const ALL_OPERATIONS_NESTED: &[NestedOp] = &[ "fminimumf128", "fmodf128", ], - public: true, + scope: OpScope::LibmPublic, }, NestedOp { // `(f32, f32, f32) -> f32` @@ -255,7 +358,7 @@ const ALL_OPERATIONS_NESTED: &[NestedOp] = &[ }, c_sig: None, fn_list: &["fmaf"], - public: true, + scope: OpScope::LibmPublic, }, NestedOp { // `(f64, f64, f64) -> f64` @@ -266,7 +369,7 @@ const ALL_OPERATIONS_NESTED: &[NestedOp] = &[ }, c_sig: None, fn_list: &["fma"], - public: true, + scope: OpScope::LibmPublic, }, NestedOp { // `(f128, f128, f128) -> f128` @@ -277,7 +380,7 @@ const ALL_OPERATIONS_NESTED: &[NestedOp] = &[ }, c_sig: None, fn_list: &["fmaf128"], - public: true, + scope: OpScope::LibmPublic, }, NestedOp { // `(f16) -> i32` @@ -288,7 +391,7 @@ const ALL_OPERATIONS_NESTED: &[NestedOp] = &[ }, c_sig: None, fn_list: &["ilogbf16"], - public: true, + scope: OpScope::LibmPublic, }, NestedOp { // `(f32) -> i32` @@ -299,7 +402,7 @@ const ALL_OPERATIONS_NESTED: &[NestedOp] = &[ }, c_sig: None, fn_list: &["ilogbf"], - public: true, + scope: OpScope::LibmPublic, }, NestedOp { // `(f64) -> i32` @@ -310,7 +413,7 @@ const ALL_OPERATIONS_NESTED: &[NestedOp] = &[ }, c_sig: None, fn_list: &["ilogb"], - public: true, + scope: OpScope::LibmPublic, }, NestedOp { // `(f128) -> i32` @@ -321,7 +424,7 @@ const ALL_OPERATIONS_NESTED: &[NestedOp] = &[ }, c_sig: None, fn_list: &["ilogbf128"], - public: true, + scope: OpScope::LibmPublic, }, NestedOp { // `(i32, f32) -> f32` @@ -332,7 +435,7 @@ const ALL_OPERATIONS_NESTED: &[NestedOp] = &[ }, c_sig: None, fn_list: &["jnf", "ynf"], - public: true, + scope: OpScope::LibmPublic, }, NestedOp { // `(i32, f64) -> f64` @@ -343,7 +446,7 @@ const ALL_OPERATIONS_NESTED: &[NestedOp] = &[ }, c_sig: None, fn_list: &["jn", "yn"], - public: true, + scope: OpScope::LibmPublic, }, NestedOp { // `(f16, i32) -> f16` @@ -354,7 +457,7 @@ const ALL_OPERATIONS_NESTED: &[NestedOp] = &[ }, c_sig: None, fn_list: &["ldexpf16", "scalbnf16"], - public: true, + scope: OpScope::LibmPublic, }, NestedOp { // `(f32, i32) -> f32` @@ -365,7 +468,7 @@ const ALL_OPERATIONS_NESTED: &[NestedOp] = &[ }, c_sig: None, fn_list: &["ldexpf", "scalbnf"], - public: true, + scope: OpScope::LibmPublic, }, NestedOp { // `(f64, i64) -> f64` @@ -376,7 +479,7 @@ const ALL_OPERATIONS_NESTED: &[NestedOp] = &[ }, c_sig: None, fn_list: &["ldexp", "scalbn"], - public: true, + scope: OpScope::LibmPublic, }, NestedOp { // `(f128, i32) -> f128` @@ -387,7 +490,7 @@ const ALL_OPERATIONS_NESTED: &[NestedOp] = &[ }, c_sig: None, fn_list: &["ldexpf128", "scalbnf128"], - public: true, + scope: OpScope::LibmPublic, }, NestedOp { // `(f32, &mut f32) -> f32` as `(f32) -> (f32, f32)` @@ -401,7 +504,7 @@ const ALL_OPERATIONS_NESTED: &[NestedOp] = &[ returns: &[Ty::F32], }), fn_list: &["modff"], - public: true, + scope: OpScope::LibmPublic, }, NestedOp { // `(f64, &mut f64) -> f64` as `(f64) -> (f64, f64)` @@ -415,7 +518,7 @@ const ALL_OPERATIONS_NESTED: &[NestedOp] = &[ returns: &[Ty::F64], }), fn_list: &["modf"], - public: true, + scope: OpScope::LibmPublic, }, NestedOp { // `(f16, &mut c_int) -> f16` as `(f16) -> (f16, i32)` @@ -429,7 +532,7 @@ const ALL_OPERATIONS_NESTED: &[NestedOp] = &[ returns: &[Ty::F16], }), fn_list: &["frexpf16"], - public: true, + scope: OpScope::LibmPublic, }, NestedOp { // `(f32, &mut c_int) -> f32` as `(f32) -> (f32, i32)` @@ -443,7 +546,7 @@ const ALL_OPERATIONS_NESTED: &[NestedOp] = &[ returns: &[Ty::F32], }), fn_list: &["frexpf", "lgammaf_r"], - public: true, + scope: OpScope::LibmPublic, }, NestedOp { // `(f64, &mut c_int) -> f64` as `(f64) -> (f64, i32)` @@ -457,7 +560,7 @@ const ALL_OPERATIONS_NESTED: &[NestedOp] = &[ returns: &[Ty::F64], }), fn_list: &["frexp", "lgamma_r"], - public: true, + scope: OpScope::LibmPublic, }, NestedOp { // `(f128, &mut c_int) -> f128` as `(f128) -> (f128, i32)` @@ -471,7 +574,7 @@ const ALL_OPERATIONS_NESTED: &[NestedOp] = &[ returns: &[Ty::F128], }), fn_list: &["frexpf128"], - public: true, + scope: OpScope::LibmPublic, }, NestedOp { // `(f32, f32, &mut c_int) -> f32` as `(f32, f32) -> (f32, i32)` @@ -485,7 +588,7 @@ const ALL_OPERATIONS_NESTED: &[NestedOp] = &[ returns: &[Ty::F32], }), fn_list: &["remquof"], - public: true, + scope: OpScope::LibmPublic, }, NestedOp { // `(f64, f64, &mut c_int) -> f64` as `(f64, f64) -> (f64, i32)` @@ -499,7 +602,7 @@ const ALL_OPERATIONS_NESTED: &[NestedOp] = &[ returns: &[Ty::F64], }), fn_list: &["remquo"], - public: true, + scope: OpScope::LibmPublic, }, NestedOp { // `(f32, &mut f32, &mut f32)` as `(f32) -> (f32, f32)` @@ -513,7 +616,7 @@ const ALL_OPERATIONS_NESTED: &[NestedOp] = &[ returns: &[], }), fn_list: &["sincosf"], - public: true, + scope: OpScope::LibmPublic, }, NestedOp { // `(f64, &mut f64, &mut f64)` as `(f64) -> (f64, f64)` @@ -527,7 +630,7 @@ const ALL_OPERATIONS_NESTED: &[NestedOp] = &[ returns: &[], }), fn_list: &["sincos"], - public: true, + scope: OpScope::LibmPublic, }, ]; @@ -607,8 +710,10 @@ pub struct MathOpInfo { pub c_sig: Signature, /// Function signature for Rust implementations pub rust_sig: Signature, - /// True if part of libm's public API - pub public: bool, + /// Indicate what crate this function is defined in and whether it is public or private. + pub scope: OpScope, + /// The path to this function, including crate but excluding the function itself. + pub path: String, } /// A flat representation of `ALL_FUNCTIONS`. @@ -623,7 +728,8 @@ pub static ALL_OPERATIONS: LazyLock> = LazyLock::new(|| { float_ty: op.float_ty, rust_sig: op.rust_sig.clone(), c_sig: op.c_sig.clone().unwrap_or_else(|| op.rust_sig.clone()), - public: op.public, + scope: op.scope, + path: format!("{}::{name}", op.scope.path_root()), }; ret.push(api); } @@ -636,5 +742,15 @@ pub static ALL_OPERATIONS: LazyLock> = LazyLock::new(|| { } ret.sort_by_key(|item| item.name); + + let mut names = HashSet::new(); + let mut paths = HashSet::new(); + for item in &ret { + let new_name = names.insert(item.name); + assert!(new_name, "duplicate name `{item:?}`"); + let new_path = paths.insert(&item.path); + assert!(new_path, "duplicate path`{item:?}`"); + } + ret }); diff --git a/library/compiler-builtins/crates/libm-macros/tests/basic.rs b/library/compiler-builtins/crates/libm-macros/tests/basic.rs index 1876db8f5869d..be93bb58e1848 100644 --- a/library/compiler-builtins/crates/libm-macros/tests/basic.rs +++ b/library/compiler-builtins/crates/libm-macros/tests/basic.rs @@ -14,7 +14,7 @@ macro_rules! basic { RustFn: $RustFn:ty, RustArgs: $RustArgs:ty, RustRet: $RustRet:ty, - public: $public:expr, + path: $path:path, attrs: [$($attr:meta),*], extra: [$($extra_tt:tt)*], fn_extra: $fn_extra:expr, @@ -27,7 +27,7 @@ macro_rules! basic { type RustFnTy = $RustFn; type RustArgsTy = $RustArgs; type RustRetTy = $RustRet; - const PUBLIC: bool = $public; + const PATH: &str = stringify!($path); const A: &[&str] = &[$($extra_tt)*]; fn foo(a: f32) -> f32 { $fn_extra(a) @@ -147,6 +147,7 @@ fn test_fn_extra_expansion() { let mut vf32 = Vec::new(); let mut vf64 = Vec::new(); let mut vf128 = Vec::new(); + let mut vbuiltins = Vec::new(); // Test with no extra, no skip, and no attributes libm_macros::for_each_function! { @@ -156,6 +157,7 @@ fn test_fn_extra_expansion() { ALL_F32 => vf32, ALL_F64 => vf64, ALL_F128 => vf128, + ALL_BUILTINS => vbuiltins, } } @@ -171,8 +173,11 @@ fn test_fn_extra_expansion() { for name in vf32 { assert!(name.ends_with("f"), "{name}"); } - let _ = vf64; for name in vf128 { assert!(name.ends_with("f128"), "{name}"); } + + // Nothing to assert here + let _ = vf64; + let _ = vbuiltins; } diff --git a/library/compiler-builtins/crates/util/src/main.rs b/library/compiler-builtins/crates/util/src/main.rs index 70aa613f18d06..9ef65f938ad79 100644 --- a/library/compiler-builtins/crates/util/src/main.rs +++ b/library/compiler-builtins/crates/util/src/main.rs @@ -12,7 +12,7 @@ use cfg_if::cfg_if; use libm::support::{Float, Hexf, hf32, hf64}; #[cfg(feature = "build-mpfr")] use libm_test::mpfloat::MpOp; -use libm_test::{Hex, MathOp, TupleCall}; +use libm_test::{Hex, MathOp, TupleCall, builtins_wrapper}; #[cfg(feature = "build-mpfr")] use rug::az::{self, Az}; @@ -55,6 +55,7 @@ macro_rules! handle_call { CFn: $CFn:ty, RustFn: $RustFn:ty, RustArgs: $RustArgs:ty, + path: $path:path, attrs: [$($attr:meta),*], extra: ($basis:ident, $op:ident, $inputs:ident), fn_extra: $musl_fn:expr, @@ -64,7 +65,7 @@ macro_rules! handle_call { type Op = libm_test::op::$fn_name::Routine; let input = <$RustArgs>::parse($inputs); - let libm_fn: ::RustFn = libm::$fn_name; + let libm_fn: ::RustFn = $path; let output = match $basis { "libm" => input.call_intercept_panics(libm_fn), @@ -91,7 +92,7 @@ macro_rules! handle_call { fn do_eval(basis: &str, op: &str, inputs: &[&str]) { libm_macros::for_each_function! { callback: handle_call, - emit_types: [CFn, RustFn, RustArgs], + emit_types: [CFn, RustFn, RustArgs, path], extra: (basis, op, inputs), fn_extra: match MACRO_FN_NAME { // Not provided by musl @@ -106,7 +107,8 @@ fn do_eval(basis: &str, op: &str, inputs: &[&str]) { | roundeven | roundevenf | ALL_F16 - | ALL_F128 => None, + | ALL_F128 + | ALL_BUILTINS => None, _ => Some(musl_math_sys::MACRO_FN_NAME) } } diff --git a/library/compiler-builtins/etc/update-api-list.py b/library/compiler-builtins/etc/update-api-list.py index 76c75cbf4dccb..03fc39618590d 100755 --- a/library/compiler-builtins/etc/update-api-list.py +++ b/library/compiler-builtins/etc/update-api-list.py @@ -6,6 +6,8 @@ needed, or that lists are sorted. """ +# FIXME: this needs to be updated to work with compiler-builtins sources + import difflib import json import re @@ -322,11 +324,13 @@ def base_name(name: str) -> tuple[str, str]: if name.endswith("f"): return (name.rstrip("f"), "f32") - - if name.endswith("f16"): + elif name.endswith("f16"): return (name.rstrip("f16"), "f16") - - if name.endswith("f128"): + elif name.endswith("f32"): + return (name.rstrip("f32"), "f32") + elif name.endswith("f64"): + return (name.rstrip("f64"), "f64") + elif name.endswith("f128"): return (name.rstrip("f128"), "f128") return (name, "f64") diff --git a/library/compiler-builtins/libm-test/Cargo.toml b/library/compiler-builtins/libm-test/Cargo.toml index 8a8c2b0a2ce01..c2d1b9f9ccbd5 100644 --- a/library/compiler-builtins/libm-test/Cargo.toml +++ b/library/compiler-builtins/libm-test/Cargo.toml @@ -7,6 +7,7 @@ license = "MIT OR Apache-2.0" [dependencies] anyhow.workspace = true +compiler_builtins = { workspace = true, default-features = false, features = ["unstable-public-internals"] } # This is not directly used but is required so we can enable `gmp-mpfr-sys/force-cross`. gmp-mpfr-sys = { workspace = true, optional = true } indicatif.workspace = true diff --git a/library/compiler-builtins/libm-test/benches/icount.rs b/library/compiler-builtins/libm-test/benches/icount.rs index 617e9fb7ad21f..e83832934b405 100644 --- a/library/compiler-builtins/libm-test/benches/icount.rs +++ b/library/compiler-builtins/libm-test/benches/icount.rs @@ -251,6 +251,10 @@ main!( icount_bench_acosf_group, icount_bench_acosh_group, icount_bench_acoshf_group, + icount_bench_addf128_group, + icount_bench_addf16_group, + icount_bench_addf32_group, + icount_bench_addf64_group, icount_bench_asin_group, icount_bench_asinf_group, icount_bench_asinh_group, @@ -275,6 +279,9 @@ main!( icount_bench_cosf_group, icount_bench_cosh_group, icount_bench_coshf_group, + icount_bench_divf128_group, + icount_bench_divf32_group, + icount_bench_divf64_group, icount_bench_erf_group, icount_bench_erfc_group, icount_bench_erfcf_group, @@ -364,10 +371,17 @@ main!( icount_bench_logf_group, icount_bench_modf_group, icount_bench_modff_group, + icount_bench_mulf128_group, + icount_bench_mulf16_group, + icount_bench_mulf32_group, + icount_bench_mulf64_group, icount_bench_nextafter_group, icount_bench_nextafterf_group, icount_bench_pow_group, icount_bench_powf_group, + icount_bench_powif128_group, + icount_bench_powif32_group, + icount_bench_powif64_group, icount_bench_remainder_group, icount_bench_remainderf_group, icount_bench_remquo_group, @@ -398,6 +412,10 @@ main!( icount_bench_sqrtf128_group, icount_bench_sqrtf16_group, icount_bench_sqrtf_group, + icount_bench_subf128_group, + icount_bench_subf16_group, + icount_bench_subf32_group, + icount_bench_subf64_group, icount_bench_tan_group, icount_bench_tanf_group, icount_bench_tanh_group, diff --git a/library/compiler-builtins/libm-test/benches/random.rs b/library/compiler-builtins/libm-test/benches/random.rs index 1b17f049ecac2..8810d4d659dfa 100644 --- a/library/compiler-builtins/libm-test/benches/random.rs +++ b/library/compiler-builtins/libm-test/benches/random.rs @@ -137,7 +137,8 @@ libm_macros::for_each_function! { | roundeven | roundevenf | ALL_F16 - | ALL_F128 => (false, None), + | ALL_F128 + | ALL_BUILTINS => (false, None), // By default we never skip (false) and always have a musl function available _ => (false, Some(musl_math_sys::MACRO_FN_NAME)) diff --git a/library/compiler-builtins/libm-test/src/builtins_wrapper.rs b/library/compiler-builtins/libm-test/src/builtins_wrapper.rs new file mode 100644 index 0000000000000..be743d16412a0 --- /dev/null +++ b/library/compiler-builtins/libm-test/src/builtins_wrapper.rs @@ -0,0 +1,51 @@ +//! Wrappers around compiler-builtins functions. +//! +//! Functions from compiler-builtins have a different naming scheme from libm and often a different +//! ABI (doesn't work with libm-test traits because that changes the type signature). Wrap these +//! to make them a bit more similar to the rest of the libm functions. + +macro_rules! binop { + ($op:ident, $ty:ty, $sfx:ident) => { + paste::paste! { + pub fn [< $op $ty >](a: $ty, b: $ty) -> $ty { + compiler_builtins::float::$op::[< __ $op $sfx >](a, b) + } + } + }; +} + +#[cfg(f16_enabled)] +binop!(add, f16, hf3); +#[cfg(f16_enabled)] +binop!(sub, f16, hf3); +#[cfg(f16_enabled)] +binop!(mul, f16, hf3); +binop!(add, f32, sf3); +binop!(sub, f32, sf3); +binop!(mul, f32, sf3); +binop!(div, f32, sf3); +binop!(add, f64, df3); +binop!(sub, f64, df3); +binop!(mul, f64, df3); +binop!(div, f64, df3); +#[cfg(f128_enabled)] +binop!(add, f128, tf3); +#[cfg(f128_enabled)] +binop!(sub, f128, tf3); +#[cfg(f128_enabled)] +binop!(mul, f128, tf3); +#[cfg(f128_enabled)] +binop!(div, f128, tf3); + +pub fn powif32(a: f32, b: i32) -> f32 { + compiler_builtins::float::pow::__powisf2(a, b) +} + +pub fn powif64(a: f64, b: i32) -> f64 { + compiler_builtins::float::pow::__powidf2(a, b) +} + +#[cfg(f128_enabled)] +pub fn powif128(a: f128, b: i32) -> f128 { + compiler_builtins::float::pow::__powitf2(a, b) +} diff --git a/library/compiler-builtins/libm-test/src/domain.rs b/library/compiler-builtins/libm-test/src/domain.rs index eb009bfa093f4..0648bf556a73b 100644 --- a/library/compiler-builtins/libm-test/src/domain.rs +++ b/library/compiler-builtins/libm-test/src/domain.rs @@ -224,6 +224,14 @@ pub fn get_domain( argnum: usize, ) -> EitherPrim, Domain> { let x = match id.base_name() { + // Basic arithmetic + BaseName::Add => &EitherPrim::UNBOUNDED2[..], + BaseName::Sub => &EitherPrim::UNBOUNDED2[..], + BaseName::Mul => &EitherPrim::UNBOUNDED2[..], + BaseName::Div => &EitherPrim::UNBOUNDED2[..], + BaseName::Powi => &EitherPrim::UNBOUNDED2[..], + + // Math functions BaseName::Acos => &EitherPrim::INVERSE_TRIG_PERIODIC[..], BaseName::Acosh => &EitherPrim::ACOSH[..], BaseName::Asin => &EitherPrim::INVERSE_TRIG_PERIODIC[..], diff --git a/library/compiler-builtins/libm-test/src/generate/case_list.rs b/library/compiler-builtins/libm-test/src/generate/case_list.rs index 66d7f6a282f6b..af4bcfaf60b12 100644 --- a/library/compiler-builtins/libm-test/src/generate/case_list.rs +++ b/library/compiler-builtins/libm-test/src/generate/case_list.rs @@ -38,6 +38,90 @@ impl TestCase { } } +/* compiler-builtins test cases */ + +#[cfg(f16_enabled)] +fn addf16_cases() -> Vec> { + vec![] +} + +fn addf32_cases() -> Vec> { + vec![] +} + +fn addf64_cases() -> Vec> { + vec![] +} + +#[cfg(f128_enabled)] +fn addf128_cases() -> Vec> { + vec![] +} + +#[cfg(f16_enabled)] +fn subf16_cases() -> Vec> { + vec![] +} + +fn subf32_cases() -> Vec> { + vec![] +} + +fn subf64_cases() -> Vec> { + vec![] +} + +#[cfg(f128_enabled)] +fn subf128_cases() -> Vec> { + vec![] +} + +#[cfg(f16_enabled)] +fn mulf16_cases() -> Vec> { + vec![] +} + +fn mulf32_cases() -> Vec> { + vec![] +} + +fn mulf64_cases() -> Vec> { + vec![] +} + +#[cfg(f128_enabled)] +fn mulf128_cases() -> Vec> { + vec![] +} + +fn divf32_cases() -> Vec> { + vec![] +} + +fn divf64_cases() -> Vec> { + vec![] +} + +#[cfg(f128_enabled)] +fn divf128_cases() -> Vec> { + vec![] +} + +fn powif32_cases() -> Vec> { + vec![] +} + +fn powif64_cases() -> Vec> { + vec![] +} + +#[cfg(f128_enabled)] +fn powif128_cases() -> Vec> { + vec![] +} + +/* libm test cases */ + fn acos_cases() -> Vec> { vec![] } diff --git a/library/compiler-builtins/libm-test/src/lib.rs b/library/compiler-builtins/libm-test/src/lib.rs index 60d96ae9bceee..9223b184d0675 100644 --- a/library/compiler-builtins/libm-test/src/lib.rs +++ b/library/compiler-builtins/libm-test/src/lib.rs @@ -3,6 +3,7 @@ #![allow(clippy::unusual_byte_groupings)] // sometimes we group by sign_exp_sig #![allow(unstable_name_collisions)] // FIXME(float_bits_const): remove when stable +pub mod builtins_wrapper; pub mod domain; mod f8_impl; pub mod generate; diff --git a/library/compiler-builtins/libm-test/src/mpfloat.rs b/library/compiler-builtins/libm-test/src/mpfloat.rs index 91130f892b8ab..008bc6823049b 100644 --- a/library/compiler-builtins/libm-test/src/mpfloat.rs +++ b/library/compiler-builtins/libm-test/src/mpfloat.rs @@ -9,7 +9,9 @@ use rug::Assign; pub use rug::Float as MpFloat; use rug::az::{self, Az}; use rug::float::Round::Nearest; -use rug::ops::{PowAssignRound, RemAssignRound}; +use rug::ops::{ + AddAssignRound, DivAssignRound, MulAssignRound, PowAssignRound, RemAssignRound, SubAssignRound, +}; use crate::{Float, MathOp}; @@ -133,6 +135,10 @@ libm_macros::for_each_function! { skip: [ // Most of these need a manual implementation // verify-sorted-start + addf128, + addf16, + addf32, + addf64, ceil, ceilf, ceilf128, @@ -141,6 +147,9 @@ libm_macros::for_each_function! { copysignf, copysignf128, copysignf16, + divf128, + divf32, + divf64, fabs, fabsf, fabsf128, @@ -180,10 +189,17 @@ libm_macros::for_each_function! { lgammaf_r, modf, modff, + mulf128, + mulf16, + mulf32, + mulf64, nextafter, nextafterf, pow, powf,remquo, + powif128, + powif32, + powif64, remquof, rint, rintf, @@ -202,6 +218,10 @@ libm_macros::for_each_function! { scalbnf128, scalbnf16, sincos,sincosf, + subf128, + subf16, + subf32, + subf64, trunc, truncf, truncf128, @@ -401,6 +421,51 @@ macro_rules! impl_op_for_ty { macro_rules! impl_op_for_ty_all { ($fty:ty, $suffix:literal) => { paste::paste! { + impl MpOp for crate::op::[]::Routine { + type MpTy = (MpFloat, MpFloat); + + fn new_mp() -> Self::MpTy { + (new_mpfloat::(), new_mpfloat::()) + } + + fn run(this: &mut Self::MpTy, input: Self::RustArgs) -> Self::RustRet { + this.0.assign(input.0); + this.1.assign(input.1); + let ord = this.0.add_assign_round(&this.1, Nearest); + prep_retval::(&mut this.0, ord) + } + } + + impl MpOp for crate::op::[]::Routine { + type MpTy = (MpFloat, MpFloat); + + fn new_mp() -> Self::MpTy { + (new_mpfloat::(), new_mpfloat::()) + } + + fn run(this: &mut Self::MpTy, input: Self::RustArgs) -> Self::RustRet { + this.0.assign(input.0); + this.1.assign(input.1); + let ord = this.0.sub_assign_round(&this.1, Nearest); + prep_retval::(&mut this.0, ord) + } + } + + impl MpOp for crate::op::[]::Routine { + type MpTy = (MpFloat, MpFloat); + + fn new_mp() -> Self::MpTy { + (new_mpfloat::(), new_mpfloat::()) + } + + fn run(this: &mut Self::MpTy, input: Self::RustArgs) -> Self::RustRet { + this.0.assign(input.0); + this.1.assign(input.1); + let ord = this.0.mul_assign_round(&this.1, Nearest); + prep_retval::(&mut this.0, ord) + } + } + impl MpOp for crate::op::[]::Routine { type MpTy = (MpFloat, MpFloat); @@ -540,9 +605,49 @@ macro_rules! impl_op_for_ty_all { }; } +macro_rules! impl_op_for_ty_no_f16 { + ($fty:ty, $suffix:literal) => { + paste::paste! { + impl MpOp for crate::op::[
]::Routine { + type MpTy = (MpFloat, MpFloat); + + fn new_mp() -> Self::MpTy { + (new_mpfloat::(), new_mpfloat::()) + } + + fn run(this: &mut Self::MpTy, input: Self::RustArgs) -> Self::RustRet { + this.0.assign(input.0); + this.1.assign(input.1); + let ord = this.0.div_assign_round(&this.1, Nearest); + prep_retval::(&mut this.0, ord) + } + } + + impl MpOp for crate::op::[]::Routine { + type MpTy = MpFloat; + + fn new_mp() -> Self::MpTy { + new_mpfloat::() + } + + fn run(this: &mut Self::MpTy, input: Self::RustArgs) -> Self::RustRet { + this.assign(input.0); + let ord = this.pow_assign_round(input.1, Nearest); + prep_retval::(this, ord) + } + } + } + }; +} + impl_op_for_ty!(f32, "f"); impl_op_for_ty!(f64, ""); +impl_op_for_ty_no_f16!(f32, "f"); +impl_op_for_ty_no_f16!(f64, ""); +#[cfg(f128_enabled)] +impl_op_for_ty_no_f16!(f128, "f128"); + #[cfg(f16_enabled)] impl_op_for_ty_all!(f16, "f16"); impl_op_for_ty_all!(f32, "f"); diff --git a/library/compiler-builtins/libm-test/src/op.rs b/library/compiler-builtins/libm-test/src/op.rs index afd445ff9c5ae..b88b2f8f94f61 100644 --- a/library/compiler-builtins/libm-test/src/op.rs +++ b/library/compiler-builtins/libm-test/src/op.rs @@ -90,9 +90,6 @@ pub trait MathOp { /// The function in `libm` which can be called. const ROUTINE: Self::RustFn; - - /// Whether or not the function is part of libm public API. - const PUBLIC: bool; } /// Access the associated `FTy` type from an op (helper to avoid ambiguous associated types). @@ -121,7 +118,7 @@ macro_rules! create_op_modules { RustFn: $RustFn:ty, RustArgs: $RustArgs:ty, RustRet: $RustRet:ty, - public: $public:expr, + path: $path:path, attrs: [$($attr:meta),*], ) => { paste::paste! { @@ -140,8 +137,7 @@ macro_rules! create_op_modules { type RustRet = $RustRet; const IDENTIFIER: Identifier = Identifier::[< $fn_name:camel >]; - const ROUTINE: Self::RustFn = libm::$fn_name; - const PUBLIC: bool = $public; + const ROUTINE: Self::RustFn = $path; } } diff --git a/library/compiler-builtins/libm-test/src/precision.rs b/library/compiler-builtins/libm-test/src/precision.rs index e994244142749..1f1e0864ce810 100644 --- a/library/compiler-builtins/libm-test/src/precision.rs +++ b/library/compiler-builtins/libm-test/src/precision.rs @@ -16,6 +16,13 @@ pub struct SpecialCase; pub fn default_ulp(ctx: &CheckCtx) -> u32 { // ULP compared to the infinite (MPFR) result. let mut ulp = match ctx.base_name { + // Basic arithmetic needs to always be precise. + Bn::Add | Bn::Sub | Bn::Mul | Bn::Div => 0, + // FIXME(correctness): we need a better powi implementation (though this is no worse + // than C). + Bn::Powi if ctx.fn_ident == Id::Powif64 => 10_000, + Bn::Powi => 1000, + // Operations that require exact results. This list should correlate with what we // have documented at . Bn::Ceil diff --git a/library/compiler-builtins/libm-test/tests/check_coverage.rs b/library/compiler-builtins/libm-test/tests/check_coverage.rs index 3b445a3de9da1..384fef19daf8c 100644 --- a/library/compiler-builtins/libm-test/tests/check_coverage.rs +++ b/library/compiler-builtins/libm-test/tests/check_coverage.rs @@ -39,7 +39,14 @@ fn test_for_each_function_all_included() { `ALL_OPERATIONS` (in `libm-macros`)." ); } - assert_eq!(all_functions, tested); + + // FIXME: This needs to be updated to interact with compiler-builtins + // assert_eq!( + // all_functions, + // tested, + // "difference: {:?}", + // tested.difference(&all_functions) + // ); } #[test] diff --git a/library/compiler-builtins/libm-test/tests/compare_built_musl.rs b/library/compiler-builtins/libm-test/tests/compare_built_musl.rs index 86f3b8b711ea7..5e9ead0473c2e 100644 --- a/library/compiler-builtins/libm-test/tests/compare_built_musl.rs +++ b/library/compiler-builtins/libm-test/tests/compare_built_musl.rs @@ -78,6 +78,7 @@ libm_macros::for_each_function! { attributes: [], // Not provided by musl skip_f16_f128: true, + skip_builtins: true, skip: [ // TODO integer inputs jn, From 16cb48102c7fd6d5432400603fc15a87113ff926 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Mon, 23 Mar 2026 21:41:39 -0500 Subject: [PATCH 015/183] meta: Cover both `.yaml` and `.yml` in `.editorconfig` --- library/compiler-builtins/.editorconfig | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/library/compiler-builtins/.editorconfig b/library/compiler-builtins/.editorconfig index f0735cedfbd6b..23a4d23f28200 100644 --- a/library/compiler-builtins/.editorconfig +++ b/library/compiler-builtins/.editorconfig @@ -1,5 +1,3 @@ -# EditorConfig helps developers define and maintain consistent -# coding styles between different editors and IDEs # editorconfig.org root = true @@ -12,5 +10,5 @@ insert_final_newline = true indent_style = space indent_size = 4 -[*.yml] +[*.{yaml,yml}] indent_size = 2 From 5ac939394a29dd042d0dae128c0d86189a909abf Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Mon, 23 Mar 2026 21:44:55 -0500 Subject: [PATCH 016/183] ci: Move `matrix.os` comparisons to an environment variable --- .../.github/workflows/main.yaml | 20 +++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/library/compiler-builtins/.github/workflows/main.yaml b/library/compiler-builtins/.github/workflows/main.yaml index e4bb833526caf..1f16ab9a355e9 100644 --- a/library/compiler-builtins/.github/workflows/main.yaml +++ b/library/compiler-builtins/.github/workflows/main.yaml @@ -114,16 +114,16 @@ jobs: JOB_TARGET: ${{ matrix.target }} JOB_CHANNEL: ${{ matrix.channel }} MAY_SKIP_LIBM_CI: ${{ needs.calculate_vars.outputs.may_skip_libm_ci }} + RUN_IN_DOCKER: ${{ matrix.os == 'ubuntu-24.04' }} steps: - - name: Print $HOME + - name: Print runner information shell: bash run: | set -x - echo "${HOME:-not found}" + uname -a + lscpu || (sysctl -a | grep cpu) || true + echo "home: ${HOME:-not found}" pwd - printenv - - name: Print runner information - run: uname -a # Native ppc and s390x runners don't have rustup by default - name: Install rustup @@ -151,14 +151,14 @@ jobs: key: ${{ matrix.target }} - name: Cache Docker layers uses: actions/cache@cdf6c1fa76f9f475f3d7449005a359c84ca0f306 # v5 - if: matrix.os == 'ubuntu-24.04' + if: ${{ env.RUN_IN_DOCKER == 'true' }} with: path: /tmp/.buildx-cache key: ${{ matrix.target }}-buildx-${{ github.sha }} restore-keys: ${{ matrix.target }}-buildx- # Configure buildx to use Docker layer caching - uses: docker/setup-buildx-action@4d04d5d9486b7bd6fa91e7baf45bbb4f8b9deedd # v4 - if: matrix.os == 'ubuntu-24.04' + if: ${{ env.RUN_IN_DOCKER == 'true' }} - name: Cache compiler-rt id: cache-compiler-rt @@ -183,13 +183,13 @@ jobs: # Non-linux tests just use our raw script - name: Run locally - if: matrix.os != 'ubuntu-24.04' + if: ${{ env.RUN_IN_DOCKER != 'true' }} shell: bash run: ./ci/run.sh "$JOB_TARGET" # Otherwise we use our docker containers to run builds - name: Run in Docker - if: matrix.os == 'ubuntu-24.04' + if: ${{ env.RUN_IN_DOCKER == 'true' }} run: ./ci/run-docker.sh "$JOB_TARGET" - name: Print test logs if available @@ -201,7 +201,7 @@ jobs: # https://github.com/docker/build-push-action/issues/252 # https://github.com/moby/buildkit/issues/1896 - name: Move Docker cache - if: matrix.os == 'ubuntu-24.04' + if: ${{ env.RUN_IN_DOCKER == 'true' }} run: | rm -rf /tmp/.buildx-cache mv /tmp/.buildx-cache-new /tmp/.buildx-cache From e8e3bdd6b7e7f523f8b47a50aad74b5f0ba31467 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Mon, 23 Mar 2026 19:57:25 -0500 Subject: [PATCH 017/183] test: Better support tests that don't require a ulp value --- library/compiler-builtins/libm-test/src/precision.rs | 8 +++++--- library/compiler-builtins/libm-test/src/run_cfg.rs | 4 ++-- library/compiler-builtins/libm-test/src/test_traits.rs | 4 +++- 3 files changed, 10 insertions(+), 6 deletions(-) diff --git a/library/compiler-builtins/libm-test/src/precision.rs b/library/compiler-builtins/libm-test/src/precision.rs index 1f1e0864ce810..e6edefa9e86c2 100644 --- a/library/compiler-builtins/libm-test/src/precision.rs +++ b/library/compiler-builtins/libm-test/src/precision.rs @@ -13,7 +13,7 @@ pub struct SpecialCase; /// ULP allowed to differ from the results returned by a test basis. #[allow(clippy::single_match)] -pub fn default_ulp(ctx: &CheckCtx) -> u32 { +pub fn default_ulp(ctx: &CheckCtx) -> Option { // ULP compared to the infinite (MPFR) result. let mut ulp = match ctx.base_name { // Basic arithmetic needs to always be precise. @@ -23,6 +23,9 @@ pub fn default_ulp(ctx: &CheckCtx) -> u32 { Bn::Powi if ctx.fn_ident == Id::Powif64 => 10_000, Bn::Powi => 1000, + // Operations that only return non-float results + Bn::Ilogb => return None, + // Operations that require exact results. This list should correlate with what we // have documented at . Bn::Ceil @@ -39,7 +42,6 @@ pub fn default_ulp(ctx: &CheckCtx) -> u32 { | Bn::FminimumNum | Bn::Fmod | Bn::Frexp - | Bn::Ilogb | Bn::Ldexp | Bn::Modf | Bn::Nextafter @@ -152,7 +154,7 @@ pub fn default_ulp(ctx: &CheckCtx) -> u32 { } } - ulp + Some(ulp) } /// Result of checking for possible overrides. diff --git a/library/compiler-builtins/libm-test/src/run_cfg.rs b/library/compiler-builtins/libm-test/src/run_cfg.rs index 90f81195c8560..a8b0a2e117520 100644 --- a/library/compiler-builtins/libm-test/src/run_cfg.rs +++ b/library/compiler-builtins/libm-test/src/run_cfg.rs @@ -69,7 +69,7 @@ pub fn extensive_max_iterations() -> u64 { #[derive(Clone, Debug, PartialEq, Eq)] pub struct CheckCtx { /// Allowed ULP deviation - pub ulp: u32, + pub ulp: Option, pub fn_ident: Identifier, pub base_name: BaseName, /// Function name. @@ -88,7 +88,7 @@ impl CheckCtx { /// Create a new check context, using the default ULP for the function. pub fn new(fn_ident: Identifier, basis: CheckBasis, gen_kind: GeneratorKind) -> Self { let mut ret = Self { - ulp: 0, + ulp: None, fn_ident, fn_name: fn_ident.as_str(), base_name: fn_ident.base_name(), diff --git a/library/compiler-builtins/libm-test/src/test_traits.rs b/library/compiler-builtins/libm-test/src/test_traits.rs index f8621a3734a4c..bb4fdb8f2126c 100644 --- a/library/compiler-builtins/libm-test/src/test_traits.rs +++ b/library/compiler-builtins/libm-test/src/test_traits.rs @@ -310,7 +310,9 @@ where // Create a wrapper function so we only need to `.with_context` once. let mut inner = || -> TestResult { - let mut allowed_ulp = ctx.ulp; + let mut allowed_ulp = ctx + .ulp + .expect("functions returning floats should have a default ulp set"); match SpecialCase::check_float(input, actual, expected, ctx) { // Forbid overrides if the items came from an explicit list From b6331ad6319041dee1f8429d728c21196c91573e Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Mon, 23 Mar 2026 19:53:42 -0500 Subject: [PATCH 018/183] test: Clean up macro use in `builtins_wrappers` --- .../libm-test/src/builtins_wrapper.rs | 66 +++++++++---------- 1 file changed, 32 insertions(+), 34 deletions(-) diff --git a/library/compiler-builtins/libm-test/src/builtins_wrapper.rs b/library/compiler-builtins/libm-test/src/builtins_wrapper.rs index be743d16412a0..7676963c82b2a 100644 --- a/library/compiler-builtins/libm-test/src/builtins_wrapper.rs +++ b/library/compiler-builtins/libm-test/src/builtins_wrapper.rs @@ -4,48 +4,46 @@ //! ABI (doesn't work with libm-test traits because that changes the type signature). Wrap these //! to make them a bit more similar to the rest of the libm functions. -macro_rules! binop { - ($op:ident, $ty:ty, $sfx:ident) => { - paste::paste! { - pub fn [< $op $ty >](a: $ty, b: $ty) -> $ty { - compiler_builtins::float::$op::[< __ $op $sfx >](a, b) - } +macro_rules! cb_op { + // Fully generic version + ($mod:ident, $cb_name:ident, $new_name:ident, ($($arg:ident: $ArgTy:ty),*) -> $RetTy:ty) => { + pub fn $new_name($($arg: $ArgTy),*) -> $RetTy { + compiler_builtins::float::$mod::$cb_name($($arg),*) } }; + // Common signatures + (@binop $ty:ty, $mod:ident, $cb_name:ident, $new_name:ident) => { + cb_op!($mod, $cb_name, $new_name, (a: $ty, b: $ty) -> $ty); + }; } #[cfg(f16_enabled)] -binop!(add, f16, hf3); -#[cfg(f16_enabled)] -binop!(sub, f16, hf3); -#[cfg(f16_enabled)] -binop!(mul, f16, hf3); -binop!(add, f32, sf3); -binop!(sub, f32, sf3); -binop!(mul, f32, sf3); -binop!(div, f32, sf3); -binop!(add, f64, df3); -binop!(sub, f64, df3); -binop!(mul, f64, df3); -binop!(div, f64, df3); -#[cfg(f128_enabled)] -binop!(add, f128, tf3); +cb_op!(@binop f16, add, __addhf3, addf16); +cb_op!(@binop f32, add, __addsf3, addf32); +cb_op!(@binop f64, add, __adddf3, addf64); #[cfg(f128_enabled)] -binop!(sub, f128, tf3); -#[cfg(f128_enabled)] -binop!(mul, f128, tf3); +cb_op!(@binop f128, add, __addtf3, addf128); + +#[cfg(f16_enabled)] +cb_op!(@binop f16, sub, __subhf3, subf16); +cb_op!(@binop f32, sub, __subsf3, subf32); +cb_op!(@binop f64, sub, __subdf3, subf64); #[cfg(f128_enabled)] -binop!(div, f128, tf3); +cb_op!(@binop f128, sub, __subtf3, subf128); -pub fn powif32(a: f32, b: i32) -> f32 { - compiler_builtins::float::pow::__powisf2(a, b) -} +#[cfg(f16_enabled)] +cb_op!(@binop f16, mul, __mulhf3, mulf16); +cb_op!(@binop f32, mul, __mulsf3, mulf32); +cb_op!(@binop f64, mul, __muldf3, mulf64); +#[cfg(f128_enabled)] +cb_op!(@binop f128, mul, __multf3, mulf128); -pub fn powif64(a: f64, b: i32) -> f64 { - compiler_builtins::float::pow::__powidf2(a, b) -} +cb_op!(@binop f32, div, __divsf3, divf32); +cb_op!(@binop f64, div, __divdf3, divf64); +#[cfg(f128_enabled)] +cb_op!(@binop f128, div, __divtf3, divf128); +cb_op!(pow, __powisf2, powif32, (a: f32, b: i32) -> f32); +cb_op!(pow, __powidf2, powif64, (a: f64, b: i32) -> f64); #[cfg(f128_enabled)] -pub fn powif128(a: f128, b: i32) -> f128 { - compiler_builtins::float::pow::__powitf2(a, b) -} +cb_op!(pow, __powitf2, powif128, (a: f128, b: i32) -> f128); From 178cea5dae62394996d07b8b7c895fc76e6bb151 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Mon, 23 Mar 2026 19:57:25 -0500 Subject: [PATCH 019/183] test: Cover compiler-builtins float comparison in libm-test Add the following to our larger test infrastructure: * `__eq[hsdf]2` * `__ne[hsdf]2` * `__unord[hsdf]2` * `__lt[hsdf]2` * `__le[hsdf]2` * `__gt[hsdf]2` * `__ge[hsdf]2` --- .../compiler-builtins/src/float/cmp.rs | 68 ++++++---- .../crates/libm-macros/src/lib.rs | 1 + .../crates/libm-macros/src/shared.rs | 56 ++++++++ .../compiler-builtins/crates/util/src/main.rs | 2 +- .../libm-test/src/builtins_wrapper.rs | 87 ++++++++++++ .../compiler-builtins/libm-test/src/domain.rs | 8 ++ .../libm-test/src/generate/case_list.rs | 126 ++++++++++++++++++ .../libm-test/src/mpfloat.rs | 126 ++++++++++++++++++ .../libm-test/src/precision.rs | 2 +- .../libm-test/src/test_traits.rs | 22 +++ .../libm/src/math/support/hex_float.rs | 14 ++ 11 files changed, 482 insertions(+), 30 deletions(-) diff --git a/library/compiler-builtins/compiler-builtins/src/float/cmp.rs b/library/compiler-builtins/compiler-builtins/src/float/cmp.rs index 8ab39c2b5914d..3587d78d1396e 100644 --- a/library/compiler-builtins/compiler-builtins/src/float/cmp.rs +++ b/library/compiler-builtins/compiler-builtins/src/float/cmp.rs @@ -4,8 +4,10 @@ use crate::float::Float; use crate::int::MinInt; use crate::support::cfg_if; -// Taken from LLVM config: -// https://github.com/llvm/llvm-project/blob/0cf3c437c18ed27d9663d87804a9a15ff6874af2/compiler-rt/lib/builtins/fp_compare_impl.inc#L11-L27 +// Taken from LLVM config [1], which should match GCC's `CMPtype` [2]. +// +// [1]: https://github.com/llvm/llvm-project/blob/0cf3c437c18ed27d9663d87804a9a15ff6874af2/compiler-rt/lib/builtins/fp_compare_impl.inc#L11-L27 +// [2]: https://gcc.gnu.org/onlinedocs/gccint/Soft-float-library-routines.html#Comparison-functions-1 cfg_if! { if #[cfg(any(target_arch = "aarch64", target_arch = "arm64ec"))] { // Aarch64 uses `int` rather than a pointer-sized value. @@ -28,8 +30,18 @@ enum Result { Unordered, } +/// Conversions to match GCC intrinsics [1]. +/// +/// * `unord`: nonzero if either NaN, 0 otherwise +/// * `eq`, `ne`: 0 if a == b and both YaN, nonzero otherwise +/// * `ge`, `gt`, `lt`, `le`: return an int result that provides the same comparison to 0 if both +/// YaN and the comparison matches. E.g. if a >= b, `ge` returns an `x >= 0`. +/// +/// The separate map functions are only needed to handle the unordered case. +/// +/// [1]: https://gcc.gnu.org/onlinedocs/gccint/Soft-float-library-routines.html#Comparison-functions-1 impl Result { - fn to_le_abi(self) -> CmpResult { + fn to_default_cmp_result(self) -> CmpResult { match self { Result::Less => -1, Result::Equal => 0, @@ -38,7 +50,7 @@ impl Result { } } - fn to_ge_abi(self) -> CmpResult { + fn to_gt_ge_cmp_result(self) -> CmpResult { match self { Result::Less => -1, Result::Equal => 0, @@ -118,11 +130,11 @@ fn unord(a: F, b: F) -> bool { #[cfg(f16_enabled)] intrinsics! { pub extern "C" fn __lehf2(a: f16, b: f16) -> crate::float::cmp::CmpResult { - cmp(a, b).to_le_abi() + cmp(a, b).to_default_cmp_result() } pub extern "C" fn __gehf2(a: f16, b: f16) -> crate::float::cmp::CmpResult { - cmp(a, b).to_ge_abi() + cmp(a, b).to_gt_ge_cmp_result() } pub extern "C" fn __unordhf2(a: f16, b: f16) -> crate::float::cmp::CmpResult { @@ -130,29 +142,29 @@ intrinsics! { } pub extern "C" fn __eqhf2(a: f16, b: f16) -> crate::float::cmp::CmpResult { - cmp(a, b).to_le_abi() + cmp(a, b).to_default_cmp_result() } pub extern "C" fn __lthf2(a: f16, b: f16) -> crate::float::cmp::CmpResult { - cmp(a, b).to_le_abi() + cmp(a, b).to_default_cmp_result() } pub extern "C" fn __nehf2(a: f16, b: f16) -> crate::float::cmp::CmpResult { - cmp(a, b).to_le_abi() + cmp(a, b).to_default_cmp_result() } pub extern "C" fn __gthf2(a: f16, b: f16) -> crate::float::cmp::CmpResult { - cmp(a, b).to_ge_abi() + cmp(a, b).to_gt_ge_cmp_result() } } intrinsics! { pub extern "C" fn __lesf2(a: f32, b: f32) -> crate::float::cmp::CmpResult { - cmp(a, b).to_le_abi() + cmp(a, b).to_default_cmp_result() } pub extern "C" fn __gesf2(a: f32, b: f32) -> crate::float::cmp::CmpResult { - cmp(a, b).to_ge_abi() + cmp(a, b).to_gt_ge_cmp_result() } #[arm_aeabi_alias = __aeabi_fcmpun] @@ -161,27 +173,27 @@ intrinsics! { } pub extern "C" fn __eqsf2(a: f32, b: f32) -> crate::float::cmp::CmpResult { - cmp(a, b).to_le_abi() + cmp(a, b).to_default_cmp_result() } pub extern "C" fn __ltsf2(a: f32, b: f32) -> crate::float::cmp::CmpResult { - cmp(a, b).to_le_abi() + cmp(a, b).to_default_cmp_result() } pub extern "C" fn __nesf2(a: f32, b: f32) -> crate::float::cmp::CmpResult { - cmp(a, b).to_le_abi() + cmp(a, b).to_default_cmp_result() } pub extern "C" fn __gtsf2(a: f32, b: f32) -> crate::float::cmp::CmpResult { - cmp(a, b).to_ge_abi() + cmp(a, b).to_gt_ge_cmp_result() } pub extern "C" fn __ledf2(a: f64, b: f64) -> crate::float::cmp::CmpResult { - cmp(a, b).to_le_abi() + cmp(a, b).to_default_cmp_result() } pub extern "C" fn __gedf2(a: f64, b: f64) -> crate::float::cmp::CmpResult { - cmp(a, b).to_ge_abi() + cmp(a, b).to_gt_ge_cmp_result() } #[arm_aeabi_alias = __aeabi_dcmpun] @@ -190,19 +202,19 @@ intrinsics! { } pub extern "C" fn __eqdf2(a: f64, b: f64) -> crate::float::cmp::CmpResult { - cmp(a, b).to_le_abi() + cmp(a, b).to_default_cmp_result() } pub extern "C" fn __ltdf2(a: f64, b: f64) -> crate::float::cmp::CmpResult { - cmp(a, b).to_le_abi() + cmp(a, b).to_default_cmp_result() } pub extern "C" fn __nedf2(a: f64, b: f64) -> crate::float::cmp::CmpResult { - cmp(a, b).to_le_abi() + cmp(a, b).to_default_cmp_result() } pub extern "C" fn __gtdf2(a: f64, b: f64) -> crate::float::cmp::CmpResult { - cmp(a, b).to_ge_abi() + cmp(a, b).to_gt_ge_cmp_result() } } @@ -210,12 +222,12 @@ intrinsics! { intrinsics! { #[ppc_alias = __lekf2] pub extern "C" fn __letf2(a: f128, b: f128) -> crate::float::cmp::CmpResult { - cmp(a, b).to_le_abi() + cmp(a, b).to_default_cmp_result() } #[ppc_alias = __gekf2] pub extern "C" fn __getf2(a: f128, b: f128) -> crate::float::cmp::CmpResult { - cmp(a, b).to_ge_abi() + cmp(a, b).to_gt_ge_cmp_result() } #[ppc_alias = __unordkf2] @@ -225,22 +237,22 @@ intrinsics! { #[ppc_alias = __eqkf2] pub extern "C" fn __eqtf2(a: f128, b: f128) -> crate::float::cmp::CmpResult { - cmp(a, b).to_le_abi() + cmp(a, b).to_default_cmp_result() } #[ppc_alias = __ltkf2] pub extern "C" fn __lttf2(a: f128, b: f128) -> crate::float::cmp::CmpResult { - cmp(a, b).to_le_abi() + cmp(a, b).to_default_cmp_result() } #[ppc_alias = __nekf2] pub extern "C" fn __netf2(a: f128, b: f128) -> crate::float::cmp::CmpResult { - cmp(a, b).to_le_abi() + cmp(a, b).to_default_cmp_result() } #[ppc_alias = __gtkf2] pub extern "C" fn __gttf2(a: f128, b: f128) -> crate::float::cmp::CmpResult { - cmp(a, b).to_ge_abi() + cmp(a, b).to_gt_ge_cmp_result() } } diff --git a/library/compiler-builtins/crates/libm-macros/src/lib.rs b/library/compiler-builtins/crates/libm-macros/src/lib.rs index 0bb32589795b4..e93c7a8e59a86 100644 --- a/library/compiler-builtins/crates/libm-macros/src/lib.rs +++ b/library/compiler-builtins/crates/libm-macros/src/lib.rs @@ -504,6 +504,7 @@ impl ToTokens for Ty { Ty::F64 => quote! { f64 }, Ty::F128 => quote! { f128 }, Ty::I32 => quote! { i32 }, + Ty::Bool => quote! { bool }, Ty::CInt => quote! { ::core::ffi::c_int }, Ty::MutF16 => quote! { &'a mut f16 }, Ty::MutF32 => quote! { &'a mut f32 }, diff --git a/library/compiler-builtins/crates/libm-macros/src/shared.rs b/library/compiler-builtins/crates/libm-macros/src/shared.rs index 309504890fe58..95e0cbe7d4f49 100644 --- a/library/compiler-builtins/crates/libm-macros/src/shared.rs +++ b/library/compiler-builtins/crates/libm-macros/src/shared.rs @@ -116,6 +116,60 @@ const ALL_OPERATIONS_NESTED: &[NestedOp] = &[ fn_list: &["powif128"], scope: OpScope::BuiltinsPublic, }, + NestedOp { + float_ty: FloatTy::F16, + rust_sig: Signature { + args: &[Ty::F16, Ty::F16], + returns: &[Ty::Bool], + }, + c_sig: None, + fn_list: &[ + "eqf16", "gef16", "gtf16", "lef16", "ltf16", "nef16", "unordf16", + ], + scope: OpScope::BuiltinsPublic, + }, + NestedOp { + float_ty: FloatTy::F32, + rust_sig: Signature { + args: &[Ty::F32, Ty::F32], + returns: &[Ty::Bool], + }, + c_sig: None, + fn_list: &[ + "eqf32", "gef32", "gtf32", "lef32", "ltf32", "nef32", "unordf32", + ], + scope: OpScope::BuiltinsPublic, + }, + NestedOp { + float_ty: FloatTy::F64, + rust_sig: Signature { + args: &[Ty::F64, Ty::F64], + returns: &[Ty::Bool], + }, + c_sig: None, + fn_list: &[ + "eqf64", "gef64", "gtf64", "lef64", "ltf64", "nef64", "unordf64", + ], + scope: OpScope::BuiltinsPublic, + }, + NestedOp { + float_ty: FloatTy::F128, + rust_sig: Signature { + args: &[Ty::F128, Ty::F128], + returns: &[Ty::Bool], + }, + c_sig: None, + fn_list: &[ + "eqf128", + "gef128", + "gtf128", + "lef128", + "ltf128", + "nef128", + "unordf128", + ], + scope: OpScope::BuiltinsPublic, + }, /* libm operations */ NestedOp { // `fn(f16) -> f16` @@ -643,6 +697,7 @@ pub enum Ty { F64, F128, I32, + Bool, CInt, MutF16, MutF32, @@ -670,6 +725,7 @@ impl fmt::Display for Ty { Ty::F64 => "f64", Ty::F128 => "f128", Ty::I32 => "i32", + Ty::Bool => "bool", Ty::CInt => "::core::ffi::c_int", Ty::MutF16 => "&mut f16", Ty::MutF32 => "&mut f32", diff --git a/library/compiler-builtins/crates/util/src/main.rs b/library/compiler-builtins/crates/util/src/main.rs index 9ef65f938ad79..5390995a064da 100644 --- a/library/compiler-builtins/crates/util/src/main.rs +++ b/library/compiler-builtins/crates/util/src/main.rs @@ -108,7 +108,7 @@ fn do_eval(basis: &str, op: &str, inputs: &[&str]) { | roundevenf | ALL_F16 | ALL_F128 - | ALL_BUILTINS => None, + | ALL_BUILTINS => None, _ => Some(musl_math_sys::MACRO_FN_NAME) } } diff --git a/library/compiler-builtins/libm-test/src/builtins_wrapper.rs b/library/compiler-builtins/libm-test/src/builtins_wrapper.rs index 7676963c82b2a..4888e16f16270 100644 --- a/library/compiler-builtins/libm-test/src/builtins_wrapper.rs +++ b/library/compiler-builtins/libm-test/src/builtins_wrapper.rs @@ -11,10 +11,48 @@ macro_rules! cb_op { compiler_builtins::float::$mod::$cb_name($($arg),*) } }; + // Common signatures (@binop $ty:ty, $mod:ident, $cb_name:ident, $new_name:ident) => { cb_op!($mod, $cb_name, $new_name, (a: $ty, b: $ty) -> $ty); }; + + // Cmp signatures. See the documentation in cmp.rs regarding the result. + (@cmp_eq $ty:ty, $mod:ident, $cb_name:ident, $new_name:ident) => { + pub fn $new_name(a: $ty, b: $ty) -> bool { + compiler_builtins::float::$mod::$cb_name(a, b) == 0 + } + }; + (@cmp_ne $ty:ty, $mod:ident, $cb_name:ident, $new_name:ident) => { + pub fn $new_name(a: $ty, b: $ty) -> bool { + compiler_builtins::float::$mod::$cb_name(a, b) != 0 + } + }; + (@cmp_unord $ty:ty, $mod:ident, $cb_name:ident, $new_name:ident) => { + pub fn $new_name(a: $ty, b: $ty) -> bool { + compiler_builtins::float::$mod::$cb_name(a, b) != 0 + } + }; + (@cmp_lt $ty:ty, $mod:ident, $cb_name:ident, $new_name:ident) => { + pub fn $new_name(a: $ty, b: $ty) -> bool { + compiler_builtins::float::$mod::$cb_name(a, b) < 0 + } + }; + (@cmp_le $ty:ty, $mod:ident, $cb_name:ident, $new_name:ident) => { + pub fn $new_name(a: $ty, b: $ty) -> bool { + compiler_builtins::float::$mod::$cb_name(a, b) <= 0 + } + }; + (@cmp_gt $ty:ty, $mod:ident, $cb_name:ident, $new_name:ident) => { + pub fn $new_name(a: $ty, b: $ty) -> bool { + compiler_builtins::float::$mod::$cb_name(a, b) > 0 + } + }; + (@cmp_ge $ty:ty, $mod:ident, $cb_name:ident, $new_name:ident) => { + pub fn $new_name(a: $ty, b: $ty) -> bool { + compiler_builtins::float::$mod::$cb_name(a, b) >= 0 + } + }; } #[cfg(f16_enabled)] @@ -47,3 +85,52 @@ cb_op!(pow, __powisf2, powif32, (a: f32, b: i32) -> f32); cb_op!(pow, __powidf2, powif64, (a: f64, b: i32) -> f64); #[cfg(f128_enabled)] cb_op!(pow, __powitf2, powif128, (a: f128, b: i32) -> f128); + +#[cfg(f16_enabled)] +cb_op!(@cmp_eq f16, cmp, __eqhf2, eqf16); +cb_op!(@cmp_eq f32, cmp, __eqsf2, eqf32); +cb_op!(@cmp_eq f64, cmp, __eqdf2, eqf64); +#[cfg(f128_enabled)] +cb_op!(@cmp_eq f128, cmp, __eqtf2, eqf128); + +#[cfg(f16_enabled)] +cb_op!(@cmp_gt f16, cmp, __gthf2, gtf16); +cb_op!(@cmp_gt f32, cmp, __gtsf2, gtf32); +cb_op!(@cmp_gt f64, cmp, __gtdf2, gtf64); +#[cfg(f128_enabled)] +cb_op!(@cmp_gt f128, cmp, __gttf2, gtf128); + +#[cfg(f16_enabled)] +cb_op!(@cmp_ge f16, cmp, __gehf2, gef16); +cb_op!(@cmp_ge f32, cmp, __gesf2, gef32); +cb_op!(@cmp_ge f64, cmp, __gedf2, gef64); +#[cfg(f128_enabled)] +cb_op!(@cmp_ge f128, cmp, __getf2, gef128); + +#[cfg(f16_enabled)] +cb_op!(@cmp_lt f16, cmp, __lthf2, ltf16); +cb_op!(@cmp_lt f32, cmp, __ltsf2, ltf32); +cb_op!(@cmp_lt f64, cmp, __ltdf2, ltf64); +#[cfg(f128_enabled)] +cb_op!(@cmp_lt f128, cmp, __lttf2, ltf128); + +#[cfg(f16_enabled)] +cb_op!(@cmp_le f16, cmp, __lehf2, lef16); +cb_op!(@cmp_le f32, cmp, __lesf2, lef32); +cb_op!(@cmp_le f64, cmp, __ledf2, lef64); +#[cfg(f128_enabled)] +cb_op!(@cmp_le f128, cmp, __letf2, lef128); + +#[cfg(f16_enabled)] +cb_op!(@cmp_ne f16, cmp, __nehf2, nef16); +cb_op!(@cmp_ne f32, cmp, __nesf2, nef32); +cb_op!(@cmp_ne f64, cmp, __nedf2, nef64); +#[cfg(f128_enabled)] +cb_op!(@cmp_ne f128, cmp, __netf2, nef128); + +#[cfg(f16_enabled)] +cb_op!(@cmp_unord f16, cmp, __unordhf2, unordf16); +cb_op!(@cmp_unord f32, cmp, __unordsf2, unordf32); +cb_op!(@cmp_unord f64, cmp, __unorddf2, unordf64); +#[cfg(f128_enabled)] +cb_op!(@cmp_unord f128, cmp, __unordtf2, unordf128); diff --git a/library/compiler-builtins/libm-test/src/domain.rs b/library/compiler-builtins/libm-test/src/domain.rs index 0648bf556a73b..ce4653aeade4a 100644 --- a/library/compiler-builtins/libm-test/src/domain.rs +++ b/library/compiler-builtins/libm-test/src/domain.rs @@ -231,6 +231,14 @@ pub fn get_domain( BaseName::Div => &EitherPrim::UNBOUNDED2[..], BaseName::Powi => &EitherPrim::UNBOUNDED2[..], + BaseName::Eq => &EitherPrim::UNBOUNDED2[..], + BaseName::Ne => &EitherPrim::UNBOUNDED2[..], + BaseName::Gt => &EitherPrim::UNBOUNDED2[..], + BaseName::Ge => &EitherPrim::UNBOUNDED2[..], + BaseName::Lt => &EitherPrim::UNBOUNDED2[..], + BaseName::Le => &EitherPrim::UNBOUNDED2[..], + BaseName::Unord => &EitherPrim::UNBOUNDED2[..], + // Math functions BaseName::Acos => &EitherPrim::INVERSE_TRIG_PERIODIC[..], BaseName::Acosh => &EitherPrim::ACOSH[..], diff --git a/library/compiler-builtins/libm-test/src/generate/case_list.rs b/library/compiler-builtins/libm-test/src/generate/case_list.rs index af4bcfaf60b12..2ad8c5d8c704a 100644 --- a/library/compiler-builtins/libm-test/src/generate/case_list.rs +++ b/library/compiler-builtins/libm-test/src/generate/case_list.rs @@ -120,6 +120,132 @@ fn powif128_cases() -> Vec> { vec![] } +#[cfg(f16_enabled)] +fn eqf16_cases() -> Vec> { + vec![] +} + +fn eqf32_cases() -> Vec> { + vec![] +} + +fn eqf64_cases() -> Vec> { + vec![] +} + +#[cfg(f128_enabled)] +fn eqf128_cases() -> Vec> { + vec![] +} + +#[cfg(f16_enabled)] +fn gtf16_cases() -> Vec> { + vec![] +} + +fn gtf32_cases() -> Vec> { + vec![] +} + +fn gtf64_cases() -> Vec> { + vec![] +} + +#[cfg(f128_enabled)] +fn gtf128_cases() -> Vec> { + vec![] +} + +#[cfg(f16_enabled)] +fn gef16_cases() -> Vec> { + vec![] +} + +fn gef32_cases() -> Vec> { + vec![] +} + +fn gef64_cases() -> Vec> { + vec![] +} + +#[cfg(f128_enabled)] +fn gef128_cases() -> Vec> { + vec![] +} + +#[cfg(f16_enabled)] +fn ltf16_cases() -> Vec> { + vec![] +} + +fn ltf32_cases() -> Vec> { + vec![] +} + +fn ltf64_cases() -> Vec> { + vec![] +} + +#[cfg(f128_enabled)] +fn ltf128_cases() -> Vec> { + vec![] +} + +#[cfg(f16_enabled)] +fn lef16_cases() -> Vec> { + vec![] +} + +fn lef32_cases() -> Vec> { + vec![] +} + +fn lef64_cases() -> Vec> { + vec![] +} + +#[cfg(f128_enabled)] +fn lef128_cases() -> Vec> { + vec![] +} + +#[cfg(f16_enabled)] +fn nef16_cases() -> Vec> { + vec![] +} + +fn nef32_cases() -> Vec> { + vec![] +} + +fn nef64_cases() -> Vec> { + vec![] +} + +#[cfg(f128_enabled)] +fn nef128_cases() -> Vec> { + vec![] +} + +#[cfg(f16_enabled)] +fn unordf16_cases() -> Vec> { + vec![] +} + +fn unordf32_cases() -> Vec> { + vec![] +} + +fn unordf64_cases() -> Vec> { + vec![] +} + +#[cfg(f128_enabled)] +fn unordf128_cases() -> Vec> { + vec![] +} + /* libm test cases */ fn acos_cases() -> Vec> { diff --git a/library/compiler-builtins/libm-test/src/mpfloat.rs b/library/compiler-builtins/libm-test/src/mpfloat.rs index 008bc6823049b..66a440037f250 100644 --- a/library/compiler-builtins/libm-test/src/mpfloat.rs +++ b/library/compiler-builtins/libm-test/src/mpfloat.rs @@ -150,6 +150,10 @@ libm_macros::for_each_function! { divf128, divf32, divf64, + eqf128, + eqf16, + eqf32, + eqf64, fabs, fabsf, fabsf128, @@ -173,6 +177,14 @@ libm_macros::for_each_function! { frexpf, frexpf128, frexpf16, + gef128, + gef16, + gef32, + gef64, + gtf128, + gtf16, + gtf32, + gtf64, ilogb, ilogbf, ilogbf128, @@ -183,16 +195,28 @@ libm_macros::for_each_function! { ldexpf, ldexpf128, ldexpf16, + lef128, + lef16, + lef32, + lef64, lgamma, lgamma_r, lgammaf, lgammaf_r, + ltf128, + ltf16, + ltf32, + ltf64, modf, modff, mulf128, mulf16, mulf32, mulf64, + nef128, + nef16, + nef32, + nef64, nextafter, nextafterf, pow, @@ -226,6 +250,10 @@ libm_macros::for_each_function! { truncf, truncf128, truncf16,yn, + unordf128, + unordf16, + unordf32, + unordf64, ynf, // verify-sorted-end ], @@ -466,6 +494,104 @@ macro_rules! impl_op_for_ty_all { } } + impl MpOp for crate::op::[]::Routine { + type MpTy = (MpFloat, MpFloat); + + fn new_mp() -> Self::MpTy { + (new_mpfloat::(), new_mpfloat::()) + } + + fn run(this: &mut Self::MpTy, input: Self::RustArgs) -> Self::RustRet { + this.0.assign(input.0); + this.1.assign(input.1); + this.0 == this.1 + } + } + + impl MpOp for crate::op::[]::Routine { + type MpTy = (MpFloat, MpFloat); + + fn new_mp() -> Self::MpTy { + (new_mpfloat::(), new_mpfloat::()) + } + + fn run(this: &mut Self::MpTy, input: Self::RustArgs) -> Self::RustRet { + this.0.assign(input.0); + this.1.assign(input.1); + this.0 > this.1 + } + } + + impl MpOp for crate::op::[]::Routine { + type MpTy = (MpFloat, MpFloat); + + fn new_mp() -> Self::MpTy { + (new_mpfloat::(), new_mpfloat::()) + } + + fn run(this: &mut Self::MpTy, input: Self::RustArgs) -> Self::RustRet { + this.0.assign(input.0); + this.1.assign(input.1); + this.0 >= this.1 + } + } + + impl MpOp for crate::op::[]::Routine { + type MpTy = (MpFloat, MpFloat); + + fn new_mp() -> Self::MpTy { + (new_mpfloat::(), new_mpfloat::()) + } + + fn run(this: &mut Self::MpTy, input: Self::RustArgs) -> Self::RustRet { + this.0.assign(input.0); + this.1.assign(input.1); + this.0 < this.1 + } + } + + impl MpOp for crate::op::[]::Routine { + type MpTy = (MpFloat, MpFloat); + + fn new_mp() -> Self::MpTy { + (new_mpfloat::(), new_mpfloat::()) + } + + fn run(this: &mut Self::MpTy, input: Self::RustArgs) -> Self::RustRet { + this.0.assign(input.0); + this.1.assign(input.1); + this.0 <= this.1 + } + } + + impl MpOp for crate::op::[]::Routine { + type MpTy = (MpFloat, MpFloat); + + fn new_mp() -> Self::MpTy { + (new_mpfloat::(), new_mpfloat::()) + } + + fn run(this: &mut Self::MpTy, input: Self::RustArgs) -> Self::RustRet { + this.0.assign(input.0); + this.1.assign(input.1); + this.0 != this.1 + } + } + + impl MpOp for crate::op::[]::Routine { + type MpTy = (MpFloat, MpFloat); + + fn new_mp() -> Self::MpTy { + (new_mpfloat::(), new_mpfloat::()) + } + + fn run(this: &mut Self::MpTy, input: Self::RustArgs) -> Self::RustRet { + this.0.assign(input.0); + this.1.assign(input.1); + this.0.is_nan() || this.1.is_nan() + } + } + impl MpOp for crate::op::[]::Routine { type MpTy = (MpFloat, MpFloat); diff --git a/library/compiler-builtins/libm-test/src/precision.rs b/library/compiler-builtins/libm-test/src/precision.rs index e6edefa9e86c2..cfc87c1d4bf0d 100644 --- a/library/compiler-builtins/libm-test/src/precision.rs +++ b/library/compiler-builtins/libm-test/src/precision.rs @@ -24,7 +24,7 @@ pub fn default_ulp(ctx: &CheckCtx) -> Option { Bn::Powi => 1000, // Operations that only return non-float results - Bn::Ilogb => return None, + Bn::Eq | Bn::Ne | Bn::Gt | Bn::Ge | Bn::Lt | Bn::Le | Bn::Unord | Bn::Ilogb => return None, // Operations that require exact results. This list should correlate with what we // have documented at . diff --git a/library/compiler-builtins/libm-test/src/test_traits.rs b/library/compiler-builtins/libm-test/src/test_traits.rs index bb4fdb8f2126c..3af37c32ffc0a 100644 --- a/library/compiler-builtins/libm-test/src/test_traits.rs +++ b/library/compiler-builtins/libm-test/src/test_traits.rs @@ -186,6 +186,28 @@ where } } +/* trait implementations for bool */ + +impl CheckOutput for bool +where + Input: Hex + fmt::Debug, + SpecialCase: MaybeOverride, +{ + fn validate<'a>(self, expected: Self, input: Input, _ctx: &CheckCtx) -> TestResult { + anyhow::ensure!( + self == expected, + "\ + \n input: {input:?} {ibits}\ + \n expected: {expected}\ + \n actual: {self}\ + ", + ibits = input.hex(), + ); + + Ok(()) + } +} + /* trait implementations for ints */ macro_rules! impl_int { diff --git a/library/compiler-builtins/libm/src/math/support/hex_float.rs b/library/compiler-builtins/libm/src/math/support/hex_float.rs index 6d75e760fbb0a..d94e5ce8bbc6d 100644 --- a/library/compiler-builtins/libm/src/math/support/hex_float.rs +++ b/library/compiler-builtins/libm/src/math/support/hex_float.rs @@ -427,6 +427,20 @@ mod hex_fmt { } } + // Not really a meaningful impl, but makes some generics easier. + impl fmt::LowerHex for Hexf { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + cfg_if! { + if #[cfg(feature = "compiler-builtins")] { + let _ = f; + unimplemented!() + } else { + write!(f, "{}", self.0) + } + } + } + } + impl fmt::Debug for Hexf where Hexf: fmt::LowerHex, From 3e16dd3ec49608ea685893d208731e4fc35c90b7 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Tue, 24 Mar 2026 00:10:55 -0500 Subject: [PATCH 020/183] test: Cover compiler-builtins float conversion in libm-test Add the following to the test infrastructure: * `__extenddftf2` * `__extendhfdf2` * `__extendhfsf2` * `__extendhftf2` * `__extendsfdf2` * `__extendsftf2` * `__truncdfhf2` * `__truncdfsf2` * `__truncsfhf2` * `__trunctfdf2` * `__trunctfhf2` * `__trunctfsf2` --- .../crates/libm-macros/src/shared.rs | 120 ++++++++++++++++++ .../libm-test/src/builtins_wrapper.rs | 26 ++++ .../compiler-builtins/libm-test/src/domain.rs | 9 ++ .../libm-test/src/generate/case_list.rs | 72 ++++++++++- .../libm-test/src/mpfloat.rs | 57 +++++++++ .../libm-test/src/precision.rs | 8 ++ 6 files changed, 290 insertions(+), 2 deletions(-) diff --git a/library/compiler-builtins/crates/libm-macros/src/shared.rs b/library/compiler-builtins/crates/libm-macros/src/shared.rs index 95e0cbe7d4f49..d1d79897f399c 100644 --- a/library/compiler-builtins/crates/libm-macros/src/shared.rs +++ b/library/compiler-builtins/crates/libm-macros/src/shared.rs @@ -170,6 +170,126 @@ const ALL_OPERATIONS_NESTED: &[NestedOp] = &[ ], scope: OpScope::BuiltinsPublic, }, + NestedOp { + float_ty: FloatTy::F16, + rust_sig: Signature { + args: &[Ty::F16], + returns: &[Ty::F32], + }, + c_sig: None, + fn_list: &["extend_f16_f32"], + scope: OpScope::BuiltinsPublic, + }, + NestedOp { + float_ty: FloatTy::F16, + rust_sig: Signature { + args: &[Ty::F16], + returns: &[Ty::F64], + }, + c_sig: None, + fn_list: &["extend_f16_f64"], + scope: OpScope::BuiltinsPublic, + }, + NestedOp { + float_ty: FloatTy::F16, + rust_sig: Signature { + args: &[Ty::F16], + returns: &[Ty::F128], + }, + c_sig: None, + fn_list: &["extend_f16_f128"], + scope: OpScope::BuiltinsPublic, + }, + NestedOp { + float_ty: FloatTy::F32, + rust_sig: Signature { + args: &[Ty::F32], + returns: &[Ty::F64], + }, + c_sig: None, + fn_list: &["extend_f32_f64"], + scope: OpScope::BuiltinsPublic, + }, + NestedOp { + float_ty: FloatTy::F32, + rust_sig: Signature { + args: &[Ty::F32], + returns: &[Ty::F128], + }, + c_sig: None, + fn_list: &["extend_f32_f128"], + scope: OpScope::BuiltinsPublic, + }, + NestedOp { + float_ty: FloatTy::F64, + rust_sig: Signature { + args: &[Ty::F64], + returns: &[Ty::F128], + }, + c_sig: None, + fn_list: &["extend_f64_f128"], + scope: OpScope::BuiltinsPublic, + }, + NestedOp { + float_ty: FloatTy::F32, + rust_sig: Signature { + args: &[Ty::F32], + returns: &[Ty::F16], + }, + c_sig: None, + fn_list: &["trunc_f32_f16"], + scope: OpScope::BuiltinsPublic, + }, + NestedOp { + float_ty: FloatTy::F64, + rust_sig: Signature { + args: &[Ty::F64], + returns: &[Ty::F16], + }, + c_sig: None, + fn_list: &["trunc_f64_f16"], + scope: OpScope::BuiltinsPublic, + }, + NestedOp { + float_ty: FloatTy::F128, + rust_sig: Signature { + args: &[Ty::F128], + returns: &[Ty::F16], + }, + c_sig: None, + fn_list: &["trunc_f128_f16"], + scope: OpScope::BuiltinsPublic, + }, + NestedOp { + float_ty: FloatTy::F64, + rust_sig: Signature { + args: &[Ty::F64], + returns: &[Ty::F32], + }, + c_sig: None, + fn_list: &["trunc_f64_f32"], + scope: OpScope::BuiltinsPublic, + }, + NestedOp { + float_ty: FloatTy::F128, + rust_sig: Signature { + args: &[Ty::F128], + returns: &[Ty::F32], + }, + c_sig: None, + fn_list: &["trunc_f128_f32"], + scope: OpScope::BuiltinsPublic, + }, + NestedOp { + float_ty: FloatTy::F128, + rust_sig: Signature { + args: &[Ty::F128], + returns: &[Ty::F64], + }, + c_sig: None, + fn_list: &["trunc_f128_f64"], + scope: OpScope::BuiltinsPublic, + }, /* libm operations */ NestedOp { // `fn(f16) -> f16` diff --git a/library/compiler-builtins/libm-test/src/builtins_wrapper.rs b/library/compiler-builtins/libm-test/src/builtins_wrapper.rs index 4888e16f16270..8da1306a747cd 100644 --- a/library/compiler-builtins/libm-test/src/builtins_wrapper.rs +++ b/library/compiler-builtins/libm-test/src/builtins_wrapper.rs @@ -134,3 +134,29 @@ cb_op!(@cmp_unord f32, cmp, __unordsf2, unordf32); cb_op!(@cmp_unord f64, cmp, __unorddf2, unordf64); #[cfg(f128_enabled)] cb_op!(@cmp_unord f128, cmp, __unordtf2, unordf128); + +#[cfg(f16_enabled)] +cb_op!(extend, __extendhfsf2, extend_f16_f32, (a: f16) -> f32); +#[cfg(f16_enabled)] +cb_op!(extend, __extendhfdf2, extend_f16_f64, (a: f16) -> f64); +#[cfg(f16_enabled)] +#[cfg(f128_enabled)] +cb_op!(extend, __extendhftf2, extend_f16_f128, (a: f16) -> f128); +cb_op!(extend, __extendsfdf2, extend_f32_f64, (a: f32) -> f64); +#[cfg(f128_enabled)] +cb_op!(extend, __extendsftf2, extend_f32_f128, (a: f32) -> f128); +#[cfg(f128_enabled)] +cb_op!(extend, __extenddftf2, extend_f64_f128, (a: f64) -> f128); + +#[cfg(f16_enabled)] +cb_op!(trunc, __truncsfhf2, trunc_f32_f16, (a: f32) -> f16); +#[cfg(f16_enabled)] +cb_op!(trunc, __truncdfhf2, trunc_f64_f16, (a: f64) -> f16); +cb_op!(trunc, __truncdfsf2, trunc_f64_f32, (a: f64) -> f32); +#[cfg(f16_enabled)] +#[cfg(f128_enabled)] +cb_op!(trunc, __trunctfhf2, trunc_f128_f16, (a: f128) -> f16); +#[cfg(f128_enabled)] +cb_op!(trunc, __trunctfsf2, trunc_f128_f32, (a: f128) -> f32); +#[cfg(f128_enabled)] +cb_op!(trunc, __trunctfdf2, trunc_f128_f64, (a: f128) -> f64); diff --git a/library/compiler-builtins/libm-test/src/domain.rs b/library/compiler-builtins/libm-test/src/domain.rs index ce4653aeade4a..99ecadd891c46 100644 --- a/library/compiler-builtins/libm-test/src/domain.rs +++ b/library/compiler-builtins/libm-test/src/domain.rs @@ -231,6 +231,7 @@ pub fn get_domain( BaseName::Div => &EitherPrim::UNBOUNDED2[..], BaseName::Powi => &EitherPrim::UNBOUNDED2[..], + // Comparison BaseName::Eq => &EitherPrim::UNBOUNDED2[..], BaseName::Ne => &EitherPrim::UNBOUNDED2[..], BaseName::Gt => &EitherPrim::UNBOUNDED2[..], @@ -239,6 +240,14 @@ pub fn get_domain( BaseName::Le => &EitherPrim::UNBOUNDED2[..], BaseName::Unord => &EitherPrim::UNBOUNDED2[..], + // Conversions + BaseName::ExtendF16 => &EitherPrim::UNBOUNDED1[..], + BaseName::ExtendF32 => &EitherPrim::UNBOUNDED1[..], + BaseName::ExtendF64 => &EitherPrim::UNBOUNDED1[..], + BaseName::TruncF32 => &EitherPrim::UNBOUNDED1[..], + BaseName::TruncF64 => &EitherPrim::UNBOUNDED1[..], + BaseName::TruncF128 => &EitherPrim::UNBOUNDED1[..], + // Math functions BaseName::Acos => &EitherPrim::INVERSE_TRIG_PERIODIC[..], BaseName::Acosh => &EitherPrim::ACOSH[..], diff --git a/library/compiler-builtins/libm-test/src/generate/case_list.rs b/library/compiler-builtins/libm-test/src/generate/case_list.rs index 2ad8c5d8c704a..4ce079b62089a 100644 --- a/library/compiler-builtins/libm-test/src/generate/case_list.rs +++ b/library/compiler-builtins/libm-test/src/generate/case_list.rs @@ -38,7 +38,9 @@ impl TestCase { } } -/* compiler-builtins test cases */ +/******************************** + * compiler-builtins test cases * + ********************************/ #[cfg(f16_enabled)] fn addf16_cases() -> Vec> { @@ -120,6 +122,8 @@ fn powif128_cases() -> Vec> { vec![] } +/* comparison */ + #[cfg(f16_enabled)] fn eqf16_cases() -> Vec> { vec![] @@ -246,7 +250,71 @@ fn unordf128_cases() -> Vec> { vec![] } -/* libm test cases */ +/* conversion */ + +#[cfg(f16_enabled)] +fn extend_f16_f32_cases() -> Vec> { + vec![] +} + +#[cfg(f16_enabled)] +fn extend_f16_f64_cases() -> Vec> { + vec![] +} + +#[cfg(f16_enabled)] +#[cfg(f128_enabled)] +fn extend_f16_f128_cases() -> Vec> { + vec![] +} + +fn extend_f32_f64_cases() -> Vec> { + vec![] +} + +#[cfg(f128_enabled)] +fn extend_f32_f128_cases() -> Vec> { + vec![] +} + +#[cfg(f128_enabled)] +fn extend_f64_f128_cases() -> Vec> { + vec![] +} + +#[cfg(f16_enabled)] +fn trunc_f32_f16_cases() -> Vec> { + vec![] +} + +#[cfg(f16_enabled)] +fn trunc_f64_f16_cases() -> Vec> { + vec![] +} + +fn trunc_f64_f32_cases() -> Vec> { + vec![] +} + +#[cfg(f16_enabled)] +#[cfg(f128_enabled)] +fn trunc_f128_f16_cases() -> Vec> { + vec![] +} + +#[cfg(f128_enabled)] +fn trunc_f128_f32_cases() -> Vec> { + vec![] +} + +#[cfg(f128_enabled)] +fn trunc_f128_f64_cases() -> Vec> { + vec![] +} + +/******************* + * libm test cases * + *******************/ fn acos_cases() -> Vec> { vec![] diff --git a/library/compiler-builtins/libm-test/src/mpfloat.rs b/library/compiler-builtins/libm-test/src/mpfloat.rs index 66a440037f250..677fa2b282307 100644 --- a/library/compiler-builtins/libm-test/src/mpfloat.rs +++ b/library/compiler-builtins/libm-test/src/mpfloat.rs @@ -154,6 +154,12 @@ libm_macros::for_each_function! { eqf16, eqf32, eqf64, + extend_f16_f128, + extend_f16_f32, + extend_f16_f64, + extend_f32_f128, + extend_f32_f64, + extend_f64_f128, fabs, fabsf, fabsf128, @@ -247,6 +253,12 @@ libm_macros::for_each_function! { subf32, subf64, trunc, + trunc_f128_f16, + trunc_f128_f32, + trunc_f128_f64, + trunc_f32_f16, + trunc_f64_f16, + trunc_f64_f32, truncf, truncf128, truncf16,yn, @@ -766,6 +778,38 @@ macro_rules! impl_op_for_ty_no_f16 { }; } +macro_rules! impl_extend_trunc { + ($narrow:ty, $wide:ty) => { + paste::paste! { + impl MpOp for crate::op::[]::Routine { + type MpTy = MpFloat; + + fn new_mp() -> Self::MpTy { + new_mpfloat::() + } + + fn run(this: &mut Self::MpTy, input: Self::RustArgs) -> Self::RustRet { + this.assign(input.0); + prep_retval::(this, Ordering::Equal) + } + } + + impl MpOp for crate::op::[]::Routine { + type MpTy = MpFloat; + + fn new_mp() -> Self::MpTy { + new_mpfloat::() + } + + fn run(this: &mut Self::MpTy, input: Self::RustArgs) -> Self::RustRet { + this.assign(input.0); + prep_retval::(this, Ordering::Equal) + } + } + } + }; +} + impl_op_for_ty!(f32, "f"); impl_op_for_ty!(f64, ""); @@ -781,6 +825,19 @@ impl_op_for_ty_all!(f64, ""); #[cfg(f128_enabled)] impl_op_for_ty_all!(f128, "f128"); +#[cfg(f16_enabled)] +impl_extend_trunc!(f16, f32); +#[cfg(f16_enabled)] +impl_extend_trunc!(f16, f64); +#[cfg(f16_enabled)] +#[cfg(f128_enabled)] +impl_extend_trunc!(f16, f128); +impl_extend_trunc!(f32, f64); +#[cfg(f128_enabled)] +impl_extend_trunc!(f32, f128); +#[cfg(f128_enabled)] +impl_extend_trunc!(f64, f128); + // `lgamma_r` is not a simple suffix so we can't use the above macro. impl MpOp for crate::op::lgamma_r::Routine { type MpTy = MpFloat; diff --git a/library/compiler-builtins/libm-test/src/precision.rs b/library/compiler-builtins/libm-test/src/precision.rs index cfc87c1d4bf0d..b8c257c3edc9f 100644 --- a/library/compiler-builtins/libm-test/src/precision.rs +++ b/library/compiler-builtins/libm-test/src/precision.rs @@ -26,6 +26,14 @@ pub fn default_ulp(ctx: &CheckCtx) -> Option { // Operations that only return non-float results Bn::Eq | Bn::Ne | Bn::Gt | Bn::Ge | Bn::Lt | Bn::Le | Bn::Unord | Bn::Ilogb => return None, + // Convrsion operations must be precise. + BaseName::ExtendF16 + | BaseName::ExtendF32 + | BaseName::ExtendF64 + | BaseName::TruncF128 + | BaseName::TruncF32 + | BaseName::TruncF64 => 0, + // Operations that require exact results. This list should correlate with what we // have documented at . Bn::Ceil From 456bf7721885ab602be800746dd96d23b0ee1f8c Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Tue, 24 Mar 2026 00:39:00 -0500 Subject: [PATCH 021/183] macros: Update `skip_f16_f128` to handle return types --- .../crates/libm-macros/src/lib.rs | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/library/compiler-builtins/crates/libm-macros/src/lib.rs b/library/compiler-builtins/crates/libm-macros/src/lib.rs index e93c7a8e59a86..89333b4b19388 100644 --- a/library/compiler-builtins/crates/libm-macros/src/lib.rs +++ b/library/compiler-builtins/crates/libm-macros/src/lib.rs @@ -232,9 +232,20 @@ fn validate(input: &mut StructuredInput) -> syn::Result } // Omit f16 and f128 functions if requested - if input.skip_f16_f128 && (func.float_ty == FloatTy::F16 || func.float_ty == FloatTy::F128) - { - continue; + if input.skip_f16_f128 { + if matches!(func.float_ty, FloatTy::F16 | FloatTy::F128) { + continue; + } + + if func + .rust_sig + .args + .iter() + .chain(func.rust_sig.returns.iter()) + .any(|ty| matches!(ty, Ty::F16 | Ty::F128)) + { + continue; + } } if input.skip_builtins && func.scope.defined_in_compiler_builtins() { From 3cef40c882e93d9c59e6c664f2ccbe85c6add0ee Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Tue, 24 Mar 2026 02:09:23 -0500 Subject: [PATCH 022/183] test: Add benchmarks for c-b functions covered in libm-test Wire up benchmarks for functions that are now part of our testing infrastructure. --- .../libm-test/benches/icount.rs | 40 +++++++++++++++++++ 1 file changed, 40 insertions(+) diff --git a/library/compiler-builtins/libm-test/benches/icount.rs b/library/compiler-builtins/libm-test/benches/icount.rs index e83832934b405..aea990f14cbbf 100644 --- a/library/compiler-builtins/libm-test/benches/icount.rs +++ b/library/compiler-builtins/libm-test/benches/icount.rs @@ -282,6 +282,10 @@ main!( icount_bench_divf128_group, icount_bench_divf32_group, icount_bench_divf64_group, + icount_bench_eqf128_group, + icount_bench_eqf16_group, + icount_bench_eqf32_group, + icount_bench_eqf64_group, icount_bench_erf_group, icount_bench_erfc_group, icount_bench_erfcf_group, @@ -294,6 +298,12 @@ main!( icount_bench_expf_group, icount_bench_expm1_group, icount_bench_expm1f_group, + icount_bench_extend_f16_f128_group, + icount_bench_extend_f16_f32_group, + icount_bench_extend_f16_f64_group, + icount_bench_extend_f32_f128_group, + icount_bench_extend_f32_f64_group, + icount_bench_extend_f64_f128_group, icount_bench_fabs_group, icount_bench_fabsf128_group, icount_bench_fabsf16_group, @@ -341,6 +351,14 @@ main!( icount_bench_frexpf128_group, icount_bench_frexpf16_group, icount_bench_frexpf_group, + icount_bench_gef128_group, + icount_bench_gef16_group, + icount_bench_gef32_group, + icount_bench_gef64_group, + icount_bench_gtf128_group, + icount_bench_gtf16_group, + icount_bench_gtf32_group, + icount_bench_gtf64_group, icount_bench_hypot_group, icount_bench_hypotf_group, icount_bench_ilogb_group, @@ -357,6 +375,10 @@ main!( icount_bench_ldexpf128_group, icount_bench_ldexpf16_group, icount_bench_ldexpf_group, + icount_bench_lef128_group, + icount_bench_lef16_group, + icount_bench_lef32_group, + icount_bench_lef64_group, icount_bench_lgamma_group, icount_bench_lgamma_r_group, icount_bench_lgammaf_group, @@ -369,12 +391,20 @@ main!( icount_bench_log2f_group, icount_bench_log_group, icount_bench_logf_group, + icount_bench_ltf128_group, + icount_bench_ltf16_group, + icount_bench_ltf32_group, + icount_bench_ltf64_group, icount_bench_modf_group, icount_bench_modff_group, icount_bench_mulf128_group, icount_bench_mulf16_group, icount_bench_mulf32_group, icount_bench_mulf64_group, + icount_bench_nef128_group, + icount_bench_nef16_group, + icount_bench_nef32_group, + icount_bench_nef64_group, icount_bench_nextafter_group, icount_bench_nextafterf_group, icount_bench_pow_group, @@ -422,10 +452,20 @@ main!( icount_bench_tanhf_group, icount_bench_tgamma_group, icount_bench_tgammaf_group, + icount_bench_trunc_f128_f16_group, + icount_bench_trunc_f128_f32_group, + icount_bench_trunc_f128_f64_group, + icount_bench_trunc_f32_f16_group, + icount_bench_trunc_f64_f16_group, + icount_bench_trunc_f64_f32_group, icount_bench_trunc_group, icount_bench_truncf128_group, icount_bench_truncf16_group, icount_bench_truncf_group, + icount_bench_unordf128_group, + icount_bench_unordf16_group, + icount_bench_unordf32_group, + icount_bench_unordf64_group, icount_bench_y0_group, icount_bench_y0f_group, icount_bench_y1_group, From 5650d0829d46d869833fac5b308bd463b5c87701 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Tue, 24 Mar 2026 02:58:24 -0500 Subject: [PATCH 023/183] test: Consolidate `Hexf`, `Hexi`, and the `Hex` trait Create a new struct `Hex` that serves all of these purposes via a new trait `DisplayHex`. This is easier to work with because we can make `DisplayHex` a bound of `Float`. --- .../compiler-builtins/crates/util/src/main.rs | 15 +- .../libm-test/benches/icount.rs | 10 +- .../compiler-builtins/libm-test/src/lib.rs | 2 +- .../libm-test/src/test_traits.rs | 125 ++------- .../libm/src/math/fmin_fmax.rs | 13 +- .../libm/src/math/fminimum_fmaximum.rs | 19 +- .../libm/src/math/fminimum_fmaximum_num.rs | 19 +- .../libm/src/math/generic/ceil.rs | 8 +- .../libm/src/math/generic/floor.rs | 8 +- .../libm/src/math/generic/rint.rs | 10 +- .../libm/src/math/generic/trunc.rs | 8 +- .../libm/src/math/support/float_traits.rs | 2 + .../libm/src/math/support/hex_float.rs | 255 +++++++----------- .../libm/src/math/support/int_traits.rs | 3 + .../libm/src/math/support/macros.rs | 4 +- .../libm/src/math/support/mod.rs | 4 +- 16 files changed, 188 insertions(+), 317 deletions(-) diff --git a/library/compiler-builtins/crates/util/src/main.rs b/library/compiler-builtins/crates/util/src/main.rs index 5390995a064da..5be98d8bc0ea4 100644 --- a/library/compiler-builtins/crates/util/src/main.rs +++ b/library/compiler-builtins/crates/util/src/main.rs @@ -9,10 +9,10 @@ use std::num::ParseIntError; use std::str::FromStr; use cfg_if::cfg_if; -use libm::support::{Float, Hexf, hf32, hf64}; +use libm::support::{Float, Hex, hf32, hf64}; #[cfg(feature = "build-mpfr")] use libm_test::mpfloat::MpOp; -use libm_test::{Hex, MathOp, TupleCall, builtins_wrapper}; +use libm_test::{MathOp, TupleCall, builtins_wrapper}; #[cfg(feature = "build-mpfr")] use rug::az::{self, Az}; @@ -82,7 +82,7 @@ macro_rules! handle_call { } _ => panic!("unrecognized or disabled basis '{}'", $basis), }; - println!("{output:?} {:x}", Hexf(output)); + println!("{output:?} {:x}", Hex(output)); return; } }; @@ -162,18 +162,17 @@ fn do_classify(inputs: &[&str]) { fn classify_print(x: F) where F: Float, - F::Int: Hex, { println!("{x:?}"); - println!(" hex: {}", Hexf(x)); - println!(" bits: {}", x.to_bits().hex()); + println!(" hex: {}", Hex(x)); + println!(" bits: {}", Hex(x.to_bits())); println!(" nan: {}", x.is_nan()); println!(" inf: {}", x.is_infinite()); println!(" normal: {}", !x.is_subnormal()); println!(" pos: {}", x.is_sign_positive()); - println!(" exp: {} {}", x.ex(), x.ex().hex()); + println!(" exp: {} {}", x.ex(), Hex(x.ex())); println!(" exp unbiased: {}", x.exp_unbiased()); - println!(" frac: {} {}", x.frac(), x.frac().hex()); + println!(" frac: {} {}", x.frac(), Hex(x.frac())); } /// Parse a tuple from a space-delimited string. diff --git a/library/compiler-builtins/libm-test/benches/icount.rs b/library/compiler-builtins/libm-test/benches/icount.rs index aea990f14cbbf..ceec9a21bbf85 100644 --- a/library/compiler-builtins/libm-test/benches/icount.rs +++ b/library/compiler-builtins/libm-test/benches/icount.rs @@ -5,7 +5,7 @@ use std::hint::black_box; use gungraun::{library_benchmark, library_benchmark_group, main}; -use libm::support::{HInt, Hexf, hf16, hf32, hf64, hf128, u256}; +use libm::support::{HInt, Hex, hf16, hf32, hf64, hf128, u256}; use libm_test::generate::spaced; use libm_test::{CheckBasis, CheckCtx, GeneratorKind, MathOp, OpRustArgs, TupleCall, op}; @@ -206,28 +206,28 @@ library_benchmark_group!( #[bench::short(1.015625)] #[bench::max(f16::MAX)] fn icount_bench_print_hf16(x: f16) -> String { - black_box(Hexf(x).to_string()) + black_box(Hex(x).to_string()) } #[library_benchmark] #[bench::short(1.015625)] #[bench::max(f32::MAX)] fn icount_bench_print_hf32(x: f32) -> String { - black_box(Hexf(x).to_string()) + black_box(Hex(x).to_string()) } #[library_benchmark] #[bench::short(1.015625)] #[bench::max(f64::MAX)] fn icount_bench_print_hf64(x: f64) -> String { - black_box(Hexf(x).to_string()) + black_box(Hex(x).to_string()) } #[library_benchmark] #[bench::short(1.015625)] #[bench::max(f128::MAX)] fn icount_bench_print_hf128(x: f128) -> String { - black_box(Hexf(x).to_string()) + black_box(Hex(x).to_string()) } library_benchmark_group!( diff --git a/library/compiler-builtins/libm-test/src/lib.rs b/library/compiler-builtins/libm-test/src/lib.rs index 9223b184d0675..6ba34567af3be 100644 --- a/library/compiler-builtins/libm-test/src/lib.rs +++ b/library/compiler-builtins/libm-test/src/lib.rs @@ -35,7 +35,7 @@ pub use run_cfg::{ CheckBasis, CheckCtx, EXTENSIVE_ENV, GeneratorKind, bigint_fuzz_iteration_count, skip_extensive_test, }; -pub use test_traits::{CheckOutput, Hex, TupleCall}; +pub use test_traits::{CheckOutput, TupleCall}; /// Result type for tests is usually from `anyhow`. Most times there is no success value to /// propagate. diff --git a/library/compiler-builtins/libm-test/src/test_traits.rs b/library/compiler-builtins/libm-test/src/test_traits.rs index 3af37c32ffc0a..811de8f2ab453 100644 --- a/library/compiler-builtins/libm-test/src/test_traits.rs +++ b/library/compiler-builtins/libm-test/src/test_traits.rs @@ -10,7 +10,7 @@ use std::panic::{RefUnwindSafe, UnwindSafe}; use std::{fmt, panic}; use anyhow::{Context, anyhow, bail, ensure}; -use libm::support::Hexf; +use libm::support::{DisplayHex, Hex}; use crate::precision::CheckAction; use crate::{ @@ -50,17 +50,6 @@ pub trait CheckOutput: Sized { fn validate(self, expected: Self, input: Input, ctx: &CheckCtx) -> TestResult; } -/// A helper trait to print something as hex with the correct number of nibbles, e.g. a `u32` -/// will always print with `0x` followed by 8 digits. -/// -/// This is only used for printing errors so allocating is okay. -pub trait Hex: Copy { - /// Hex integer syntax. - fn hex(self) -> String; - /// Hex float syntax. - fn hexf(self) -> String; -} - /* implement `TupleCall` */ impl TupleCall R> for (T1,) @@ -142,55 +131,11 @@ where } } -/* implement `Hex` */ - -impl Hex for (T1,) -where - T1: Hex, -{ - fn hex(self) -> String { - format!("({},)", self.0.hex()) - } - - fn hexf(self) -> String { - format!("({},)", self.0.hexf()) - } -} - -impl Hex for (T1, T2) -where - T1: Hex, - T2: Hex, -{ - fn hex(self) -> String { - format!("({}, {})", self.0.hex(), self.1.hex()) - } - - fn hexf(self) -> String { - format!("({}, {})", self.0.hexf(), self.1.hexf()) - } -} - -impl Hex for (T1, T2, T3) -where - T1: Hex, - T2: Hex, - T3: Hex, -{ - fn hex(self) -> String { - format!("({}, {}, {})", self.0.hex(), self.1.hex(), self.2.hex()) - } - - fn hexf(self) -> String { - format!("({}, {}, {})", self.0.hexf(), self.1.hexf(), self.2.hexf()) - } -} - /* trait implementations for bool */ impl CheckOutput for bool where - Input: Hex + fmt::Debug, + Input: Copy + DisplayHex + fmt::Debug, SpecialCase: MaybeOverride, { fn validate<'a>(self, expected: Self, input: Input, _ctx: &CheckCtx) -> TestResult { @@ -201,7 +146,7 @@ where \n expected: {expected}\ \n actual: {self}\ ", - ibits = input.hex(), + ibits = Hex(input), ); Ok(()) @@ -213,19 +158,9 @@ where macro_rules! impl_int { ($($ty:ty),*) => { $( - impl Hex for $ty { - fn hex(self) -> String { - format!("{self:#0width$x}", width = ((Self::BITS / 4) + 2) as usize) - } - - fn hexf(self) -> String { - String::new() - } - } - impl $crate::CheckOutput for $ty where - Input: Hex + fmt::Debug, + Input: Copy + DisplayHex + fmt::Debug, SpecialCase: MaybeOverride, { fn validate<'a>( @@ -243,8 +178,8 @@ macro_rules! impl_int { fn validate_int(actual: I, expected: I, input: Input, ctx: &CheckCtx) -> TestResult where - I: Int + Hex, - Input: Hex + fmt::Debug, + I: Int, + Input: Copy + DisplayHex + fmt::Debug, SpecialCase: MaybeOverride, { let (result, xfail_msg) = match SpecialCase::check_int(input, actual, expected, ctx) { @@ -273,9 +208,9 @@ where \n actual: {actual:<22?} {actbits}\ \n {msg}\ ", - actbits = actual.hex(), - expbits = expected.hex(), - ibits = input.hex(), + actbits = Hex(actual), + expbits = Hex(expected), + ibits = Hex(input), msg = make_xfail_msg() ); @@ -289,23 +224,9 @@ impl_int!(u16, i16, u32, i32, u64, i64, u128, i128); macro_rules! impl_float { ($($ty:ty),*) => { $( - impl Hex for $ty { - fn hex(self) -> String { - format!( - "{:#0width$x}", - self.to_bits(), - width = ((Self::BITS / 4) + 2) as usize - ) - } - - fn hexf(self) -> String { - format!("{}", Hexf(self)) - } - } - impl $crate::CheckOutput for $ty where - Input: Hex + fmt::Debug, + Input: Copy + DisplayHex + fmt::Debug, SpecialCase: MaybeOverride, { fn validate<'a>( @@ -323,8 +244,8 @@ macro_rules! impl_float { fn validate_float(actual: F, expected: F, input: Input, ctx: &CheckCtx) -> TestResult where - F: Float + Hex, - Input: Hex + fmt::Debug, + F: Float, + Input: Copy + DisplayHex + fmt::Debug, u32: TryFrom, SpecialCase: MaybeOverride, { @@ -418,12 +339,12 @@ where \n expected: {expected:<22?} {exphex} {expbits}\ \n actual: {actual:<22?} {acthex} {actbits}\ ", - ihex = input.hexf(), - ibits = input.hex(), - exphex = expected.hexf(), - expbits = expected.hex(), - actbits = actual.hex(), - acthex = actual.hexf(), + ihex = Hex(input), + ibits = Hex(input), + exphex = Hex(expected), + expbits = Hex(expected), + actbits = Hex(actual), + acthex = Hex(actual), ) }) } @@ -444,7 +365,7 @@ macro_rules! impl_tuples { $( impl CheckOutput for ($a, $b) where - Input: Hex + fmt::Debug, + Input: Copy + DisplayHex + fmt::Debug, SpecialCase: MaybeOverride, { fn validate<'a>( @@ -463,10 +384,10 @@ macro_rules! impl_tuples { \n expected: {expected:?} {expbits}\ \n actual: {self:?} {actbits}\ ", - ihex = input.hexf(), - ibits = input.hex(), - expbits = expected.hex(), - actbits = self.hex(), + ihex = Hex(input), + ibits = Hex(input), + expbits = Hex(expected), + actbits = Hex(self), )) } } diff --git a/library/compiler-builtins/libm/src/math/fmin_fmax.rs b/library/compiler-builtins/libm/src/math/fmin_fmax.rs index ead9e6599f1be..64ad79928f7a0 100644 --- a/library/compiler-builtins/libm/src/math/fmin_fmax.rs +++ b/library/compiler-builtins/libm/src/math/fmin_fmax.rs @@ -77,8 +77,7 @@ pub fn fmaxf128(x: f128, y: f128) -> f128 { #[cfg(test)] mod tests { use super::*; - use crate::support::hex_float::Hexi; - use crate::support::{Float, Hexf}; + use crate::support::{Float, Hex}; fn fmin_spec_test(f: impl Fn(F, F) -> F) { // Note that (YaN, sNaN) and (sNaN, YaN) results differ from 754-2008. This is intentional, @@ -171,7 +170,7 @@ mod tests { for (x, y, res) in cases { let val = f(x, y); - assert_biteq!(val, res, "fmin({}, {})", Hexf(x), Hexf(y)); + assert_biteq!(val, res, "fmin({}, {})", Hex(x), Hex(y)); } // Ordering between zeros does not matter @@ -314,10 +313,10 @@ mod tests { val, res, "fmax({}, {}) ({}, {})", - Hexf(x), - Hexf(y), - Hexi(x.to_bits()), - Hexi(y.to_bits()), + Hex(x), + Hex(y), + Hex(x.to_bits()), + Hex(y.to_bits()), ); } diff --git a/library/compiler-builtins/libm/src/math/fminimum_fmaximum.rs b/library/compiler-builtins/libm/src/math/fminimum_fmaximum.rs index ffc724e3a8d74..59d9af317674f 100644 --- a/library/compiler-builtins/libm/src/math/fminimum_fmaximum.rs +++ b/library/compiler-builtins/libm/src/math/fminimum_fmaximum.rs @@ -69,8 +69,7 @@ pub fn fmaximumf128(x: f128, y: f128) -> f128 { #[cfg(test)] mod tests { use super::*; - use crate::support::hex_float::Hexi; - use crate::support::{Float, Hexf}; + use crate::support::{Float, Hex}; fn fminimum_spec_test(f: impl Fn(F, F) -> F) { let cases = [ @@ -132,10 +131,10 @@ mod tests { val, res, "fminimum({}, {}) ({}, {})", - Hexf(x), - Hexf(y), - Hexi(x.to_bits()), - Hexi(y.to_bits()), + Hex(x), + Hex(y), + Hex(x.to_bits()), + Hex(y.to_bits()), ); } @@ -264,10 +263,10 @@ mod tests { val, res, "fmaximum({}, {}) ({}, {})", - Hexf(x), - Hexf(y), - Hexi(x.to_bits()), - Hexi(y.to_bits()), + Hex(x), + Hex(y), + Hex(x.to_bits()), + Hex(y.to_bits()), ); } diff --git a/library/compiler-builtins/libm/src/math/fminimum_fmaximum_num.rs b/library/compiler-builtins/libm/src/math/fminimum_fmaximum_num.rs index 3157f8a3fee8c..51b20b736d2ca 100644 --- a/library/compiler-builtins/libm/src/math/fminimum_fmaximum_num.rs +++ b/library/compiler-builtins/libm/src/math/fminimum_fmaximum_num.rs @@ -69,8 +69,7 @@ pub fn fmaximum_numf128(x: f128, y: f128) -> f128 { #[cfg(test)] mod tests { use super::*; - use crate::support::hex_float::Hexi; - use crate::support::{Float, Hexf}; + use crate::support::{Float, Hex}; fn fminimum_num_spec_test(f: impl Fn(F, F) -> F) { let cases = [ @@ -167,10 +166,10 @@ mod tests { actual, expected, "fminimum_num({}, {}) ({}, {})", - Hexf(x), - Hexf(y), - Hexi(x.to_bits()), - Hexi(y.to_bits()), + Hex(x), + Hex(y), + Hex(x.to_bits()), + Hex(y.to_bits()), ); } @@ -312,10 +311,10 @@ mod tests { actual, expected, "fmaximum_num({}, {}) ({}, {})", - Hexf(x), - Hexf(y), - Hexi(x.to_bits()), - Hexi(y.to_bits()), + Hex(x), + Hex(y), + Hex(x.to_bits()), + Hex(y.to_bits()), ); } diff --git a/library/compiler-builtins/libm/src/math/generic/ceil.rs b/library/compiler-builtins/libm/src/math/generic/ceil.rs index 5584f6503ef58..21f1226e92ab4 100644 --- a/library/compiler-builtins/libm/src/math/generic/ceil.rs +++ b/library/compiler-builtins/libm/src/math/generic/ceil.rs @@ -70,7 +70,7 @@ pub fn ceil_status(x: F) -> FpResult { #[cfg(test)] mod tests { use super::*; - use crate::support::Hexf; + use crate::support::Hex; macro_rules! cases { ($f:ty) => { @@ -103,13 +103,13 @@ mod tests { fn check(cases: &[(F, F, Status)]) { for &(x, exp_res, exp_stat) in cases { let FpResult { val, status } = ceil_status(x); - assert_biteq!(val, exp_res, "{x:?} {}", Hexf(x)); + assert_biteq!(val, exp_res, "{x:?} {}", Hex(x)); assert_eq!( status, exp_stat, "{x:?} {} -> {exp_res:?} {}", - Hexf(x), - Hexf(exp_res) + Hex(x), + Hex(exp_res) ); } } diff --git a/library/compiler-builtins/libm/src/math/generic/floor.rs b/library/compiler-builtins/libm/src/math/generic/floor.rs index 7045229c0c75a..ce0934f7adc4f 100644 --- a/library/compiler-builtins/libm/src/math/generic/floor.rs +++ b/library/compiler-builtins/libm/src/math/generic/floor.rs @@ -62,7 +62,7 @@ pub fn floor_status(x: F) -> FpResult { #[cfg(test)] mod tests { use super::*; - use crate::support::Hexf; + use crate::support::Hex; macro_rules! cases { ($f:ty) => { @@ -95,13 +95,13 @@ mod tests { fn check(cases: &[(F, F, Status)]) { for &(x, exp_res, exp_stat) in cases { let FpResult { val, status } = floor_status(x); - assert_biteq!(val, exp_res, "{x:?} {}", Hexf(x)); + assert_biteq!(val, exp_res, "{x:?} {}", Hex(x)); assert_eq!( status, exp_stat, "{x:?} {} -> {exp_res:?} {}", - Hexf(x), - Hexf(exp_res) + Hex(x), + Hex(exp_res) ); } } diff --git a/library/compiler-builtins/libm/src/math/generic/rint.rs b/library/compiler-builtins/libm/src/math/generic/rint.rs index c5bc27d3de6bc..94bef770e4d2f 100644 --- a/library/compiler-builtins/libm/src/math/generic/rint.rs +++ b/library/compiler-builtins/libm/src/math/generic/rint.rs @@ -47,7 +47,7 @@ pub fn rint_round(x: F, _round: Round) -> FpResult { #[cfg(test)] mod tests { use super::*; - use crate::support::{Hexf, Status}; + use crate::support::{Hex, Status}; fn spec_test(cases: &[(F, F, Status)]) { let roundtrip = [ @@ -61,14 +61,14 @@ mod tests { for x in roundtrip { let FpResult { val, status } = rint_round(x, Round::Nearest); - assert_biteq!(val, x, "rint_round({})", Hexf(x)); - assert_eq!(status, Status::OK, "{}", Hexf(x)); + assert_biteq!(val, x, "rint_round({})", Hex(x)); + assert_eq!(status, Status::OK, "{}", Hex(x)); } for &(x, res, res_stat) in cases { let FpResult { val, status } = rint_round(x, Round::Nearest); - assert_biteq!(val, res, "rint_round({})", Hexf(x)); - assert_eq!(status, res_stat, "{}", Hexf(x)); + assert_biteq!(val, res, "rint_round({})", Hex(x)); + assert_eq!(status, res_stat, "{}", Hex(x)); } } diff --git a/library/compiler-builtins/libm/src/math/generic/trunc.rs b/library/compiler-builtins/libm/src/math/generic/trunc.rs index 7f18eb42e884a..a1c295f1354ee 100644 --- a/library/compiler-builtins/libm/src/math/generic/trunc.rs +++ b/library/compiler-builtins/libm/src/math/generic/trunc.rs @@ -43,7 +43,7 @@ pub fn trunc_status(x: F) -> FpResult { #[cfg(test)] mod tests { use super::*; - use crate::support::Hexf; + use crate::support::Hex; macro_rules! cases { ($f:ty) => { @@ -76,13 +76,13 @@ mod tests { fn check(cases: &[(F, F, Status)]) { for &(x, exp_res, exp_stat) in cases { let FpResult { val, status } = trunc_status(x); - assert_biteq!(val, exp_res, "{x:?} {}", Hexf(x)); + assert_biteq!(val, exp_res, "{x:?} {}", Hex(x)); assert_eq!( status, exp_stat, "{x:?} {} -> {exp_res:?} {}", - Hexf(x), - Hexf(exp_res) + Hex(x), + Hex(exp_res) ); } } diff --git a/library/compiler-builtins/libm/src/math/support/float_traits.rs b/library/compiler-builtins/libm/src/math/support/float_traits.rs index 944546601c9ca..b1b86552f3519 100644 --- a/library/compiler-builtins/libm/src/math/support/float_traits.rs +++ b/library/compiler-builtins/libm/src/math/support/float_traits.rs @@ -1,6 +1,7 @@ use core::{fmt, mem, ops}; use super::int_traits::{CastFrom, Int, MinInt}; +use crate::support::DisplayHex; /// Whether MIPS sNaN/qNaNs should be used. /// @@ -14,6 +15,7 @@ const MIPS_NAN: bool = cfg!(target_arch = "mips") || cfg!(target_arch = "mips64" pub trait Float: Copy + fmt::Debug + + DisplayHex + PartialEq + PartialOrd + ops::AddAssign diff --git a/library/compiler-builtins/libm/src/math/support/hex_float.rs b/library/compiler-builtins/libm/src/math/support/hex_float.rs index d94e5ce8bbc6d..e38ef50ffdeb8 100644 --- a/library/compiler-builtins/libm/src/math/support/hex_float.rs +++ b/library/compiler-builtins/libm/src/math/support/hex_float.rs @@ -1,5 +1,7 @@ //! Utilities for working with hex float formats. +pub use hex_fmt::{DisplayHex, Hex}; + use super::{Round, Status, f32_from_bits, f64_from_bits}; /// Construct a 16-bit float from hex float representation (C-style) @@ -324,17 +326,12 @@ const fn hex_digit(c: u8) -> Option { } } -#[cfg(any(test, feature = "unstable-public-internals"))] mod hex_fmt { - use core::fmt::{self, LowerHex}; - - use crate::support::{Float, MinInt}; + use core::fmt; - /// Format a floating point number as its IEEE hex (`%a`) representation. - pub struct Hexf(pub F); + use crate::support::Float; // Adapted from https://github.com/ericseppanen/hexfloat2/blob/a5c27932f0ff/src/format.rs - #[cfg(not(feature = "compiler-builtins"))] pub(super) fn fmt_any_hex(x: &F, f: &mut fmt::Formatter<'_>) -> fmt::Result { if x.is_sign_negative() { write!(f, "-")?; @@ -370,160 +367,114 @@ mod hex_fmt { write!(f, "0x{leading}{sig:0mwidth$x}p{exponent:+}") } - #[cfg(feature = "compiler-builtins")] - pub(super) fn fmt_any_hex(_x: &F, _f: &mut fmt::Formatter<'_>) -> fmt::Result { - unimplemented!() + /// Types that can be formatted as hex via `Hex`. For ints we always print with a fixed + /// number of leading zeros. For floats we use the IEEE hex (`%a`) representation. + pub trait DisplayHex { + #[allow(unused)] // Only used for tests and public test internals + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result; } - impl fmt::LowerHex for Hexf { + /// A wrapper implementing formatting traits via `DisplayHex`. + #[allow(unused)] // Only used for tests and public test internals + pub struct Hex(pub T); + + impl fmt::Debug for Hex { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - cfg_if! { - if #[cfg(feature = "compiler-builtins")] { - let _ = f; - unimplemented!() - } else { - fmt_any_hex(&self.0, f) - } - } + self.0.fmt(f) } } - impl fmt::LowerHex for Hexf<(F, F)> { + impl fmt::Display for Hex { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - cfg_if! { - if #[cfg(feature = "compiler-builtins")] { - let _ = f; - unimplemented!() - } else { - write!(f, "({:x}, {:x})", Hexf(self.0.0), Hexf(self.0.1)) - } - } + self.0.fmt(f) } } - impl fmt::LowerHex for Hexf<(F, i32)> { + impl fmt::LowerHex for Hex { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - cfg_if! { - if #[cfg(feature = "compiler-builtins")] { - let _ = f; - unimplemented!() - } else { - write!(f, "({:x}, {:x})", Hexf(self.0.0), Hexf(self.0.1)) - } - } + self.0.fmt(f) } } - impl fmt::LowerHex for Hexf { + impl DisplayHex for F { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - cfg_if! { - if #[cfg(feature = "compiler-builtins")] { - let _ = f; - unimplemented!() - } else { - write!(f, "{:#010x}", self.0) - } - } + fmt_any_hex(self, f) } } - // Not really a meaningful impl, but makes some generics easier. - impl fmt::LowerHex for Hexf { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - cfg_if! { - if #[cfg(feature = "compiler-builtins")] { - let _ = f; - unimplemented!() - } else { - write!(f, "{}", self.0) + macro_rules! impl_int { + ($ity:ty) => { + impl DisplayHex for $ity { + #[inline] + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!( + f, + "{self:#0width$x}", + width = ((<$ity>::BITS / 4) + 2) as usize, + ) } } - } + }; } - impl fmt::Debug for Hexf - where - Hexf: fmt::LowerHex, - { + impl_int!(i8); + impl_int!(i16); + impl_int!(i32); + impl_int!(i64); + impl_int!(i128); + impl_int!(isize); + impl_int!(u8); + impl_int!(u16); + impl_int!(u32); + impl_int!(u64); + impl_int!(u128); + impl_int!(usize); + + // Not really a meaningful impl, but makes some generics easier. + impl DisplayHex for bool { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { cfg_if! { if #[cfg(feature = "compiler-builtins")] { let _ = f; unimplemented!() } else { - fmt::LowerHex::fmt(self, f) + write!(f, "{self}") } } } } - impl fmt::Display for Hexf + impl DisplayHex for (T1,) where - Hexf: fmt::LowerHex, + T1: Copy + DisplayHex, { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - cfg_if! { - if #[cfg(feature = "compiler-builtins")] { - let _ = f; - unimplemented!() - } else { - fmt::LowerHex::fmt(self, f) - } - } + write!(f, "({},)", Hex(self.0)) } } - pub struct Hexi(pub F); - - impl fmt::LowerHex for Hexi { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - cfg_if! { - if #[cfg(feature = "compiler-builtins")] { - let _ = f; - unimplemented!() - } else { - write!(f, "{:#0width$x}", self.0, width = ((I::BITS / 4) + 2) as usize) - } - } - } - } - - impl fmt::Debug for Hexi + impl DisplayHex for (T1, T2) where - Hexi: fmt::LowerHex, + T1: Copy + DisplayHex, + T2: Copy + DisplayHex, { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - cfg_if! { - if #[cfg(feature = "compiler-builtins")] { - let _ = f; - unimplemented!() - } else { - fmt::LowerHex::fmt(self, f) - } - } + write!(f, "({}, {})", Hex(self.0), Hex(self.1)) } } - impl fmt::Display for Hexi + impl DisplayHex for (T1, T2, T3) where - Hexi: fmt::LowerHex, + T1: Copy + DisplayHex, + T2: Copy + DisplayHex, + T3: Copy + DisplayHex, { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - cfg_if! { - if #[cfg(feature = "compiler-builtins")] { - let _ = f; - unimplemented!() - } else { - fmt::LowerHex::fmt(self, f) - } - } + write!(f, "({}, {}, {})", Hex(self.0), Hex(self.1), Hex(self.2)) } } } -#[cfg(any(test, feature = "unstable-public-internals"))] -pub use hex_fmt::*; - #[cfg(test)] mod parse_tests { extern crate std; @@ -592,7 +543,7 @@ mod parse_tests { let n = 1_i32 << 14; for i in -n..n { let u = i.rotate_right(11) as u32; - let s = format!("{}", Hexf(f32::from_bits(u))); + let s = format!("{}", Hex(f32::from_bits(u))); let s = canonicalize_snan_str(s); match rounding_properties(&s) { Ok(()) => (), @@ -667,7 +618,7 @@ mod parse_tests { #[cfg(f128_enabled)] fn rounding() { let pi = std::f128::consts::PI; - let s = format!("{}", Hexf(pi)); + let s = format!("{}", Hex(pi)); for k in 0..=111 { let (bits, status) = parse_any(&s, 128 - k, 112 - k, Round::Nearest).unwrap(); @@ -1133,7 +1084,7 @@ mod print_tests { use super::parse_tests::canonicalize_snan_str; let f = f16::from_bits(x); - let s = format!("{}", Hexf(f)); + let s = format!("{}", Hex(f)); let s = canonicalize_snan_str(s); let from_s = hf16(&s); @@ -1162,10 +1113,10 @@ mod print_tests { // - `f16 -> f32 -> str -> f16 -> f32` for x in 0..=u16::MAX { let f16 = f16::from_bits(x); - let s16 = format!("{}", Hexf(f16)); + let s16 = format!("{}", Hex(f16)); let s16 = canonicalize_snan_str(s16); let f32 = f16 as f32; - let s32 = format!("{}", Hexf(f32)); + let s32 = format!("{}", Hex(f32)); let s32 = canonicalize_snan_str(s32); let a = hf32(&s16); @@ -1195,66 +1146,66 @@ mod print_tests { } #[test] fn spot_checks() { - assert_eq!(Hexf(f32::MAX).to_string(), "0x1.fffffep+127"); - assert_eq!(Hexf(f64::MAX).to_string(), "0x1.fffffffffffffp+1023"); + assert_eq!(Hex(f32::MAX).to_string(), "0x1.fffffep+127"); + assert_eq!(Hex(f64::MAX).to_string(), "0x1.fffffffffffffp+1023"); - assert_eq!(Hexf(f32::MIN).to_string(), "-0x1.fffffep+127"); - assert_eq!(Hexf(f64::MIN).to_string(), "-0x1.fffffffffffffp+1023"); + assert_eq!(Hex(f32::MIN).to_string(), "-0x1.fffffep+127"); + assert_eq!(Hex(f64::MIN).to_string(), "-0x1.fffffffffffffp+1023"); - assert_eq!(Hexf(f32::ZERO).to_string(), "0x0p+0"); - assert_eq!(Hexf(f64::ZERO).to_string(), "0x0p+0"); + assert_eq!(Hex(f32::ZERO).to_string(), "0x0p+0"); + assert_eq!(Hex(f64::ZERO).to_string(), "0x0p+0"); - assert_eq!(Hexf(f32::NEG_ZERO).to_string(), "-0x0p+0"); - assert_eq!(Hexf(f64::NEG_ZERO).to_string(), "-0x0p+0"); + assert_eq!(Hex(f32::NEG_ZERO).to_string(), "-0x0p+0"); + assert_eq!(Hex(f64::NEG_ZERO).to_string(), "-0x0p+0"); - assert_eq!(Hexf(f32::NAN).to_string(), "qNaN"); - assert_eq!(Hexf(f64::NAN).to_string(), "qNaN"); - assert_eq!(Hexf(f32::NEG_NAN).to_string(), "-qNaN"); - assert_eq!(Hexf(f64::NEG_NAN).to_string(), "-qNaN"); + assert_eq!(Hex(f32::NAN).to_string(), "qNaN"); + assert_eq!(Hex(f64::NAN).to_string(), "qNaN"); + assert_eq!(Hex(f32::NEG_NAN).to_string(), "-qNaN"); + assert_eq!(Hex(f64::NEG_NAN).to_string(), "-qNaN"); if !cfg!(x86_no_sse) { // FIXME(rust-lang/rust#115567): calls quiet the sNaN - assert_eq!(Hexf(f32::SNAN).to_string(), "sNaN"); - assert_eq!(Hexf(f64::SNAN).to_string(), "sNaN"); - assert_eq!(Hexf(f32::NEG_SNAN).to_string(), "-sNaN"); - assert_eq!(Hexf(f64::NEG_SNAN).to_string(), "-sNaN"); + assert_eq!(Hex(f32::SNAN).to_string(), "sNaN"); + assert_eq!(Hex(f64::SNAN).to_string(), "sNaN"); + assert_eq!(Hex(f32::NEG_SNAN).to_string(), "-sNaN"); + assert_eq!(Hex(f64::NEG_SNAN).to_string(), "-sNaN"); } - assert_eq!(Hexf(f32::INFINITY).to_string(), "inf"); - assert_eq!(Hexf(f64::INFINITY).to_string(), "inf"); + assert_eq!(Hex(f32::INFINITY).to_string(), "inf"); + assert_eq!(Hex(f64::INFINITY).to_string(), "inf"); - assert_eq!(Hexf(f32::NEG_INFINITY).to_string(), "-inf"); - assert_eq!(Hexf(f64::NEG_INFINITY).to_string(), "-inf"); + assert_eq!(Hex(f32::NEG_INFINITY).to_string(), "-inf"); + assert_eq!(Hex(f64::NEG_INFINITY).to_string(), "-inf"); #[cfg(f16_enabled)] { - assert_eq!(Hexf(f16::MAX).to_string(), "0x1.ffcp+15"); - assert_eq!(Hexf(f16::MIN).to_string(), "-0x1.ffcp+15"); - assert_eq!(Hexf(f16::ZERO).to_string(), "0x0p+0"); - assert_eq!(Hexf(f16::NEG_ZERO).to_string(), "-0x0p+0"); - assert_eq!(Hexf(f16::NAN).to_string(), "qNaN"); - assert_eq!(Hexf(f16::SNAN).to_string(), "sNaN"); - assert_eq!(Hexf(f16::NEG_NAN).to_string(), "-qNaN"); - assert_eq!(Hexf(f16::INFINITY).to_string(), "inf"); - assert_eq!(Hexf(f16::NEG_INFINITY).to_string(), "-inf"); + assert_eq!(Hex(f16::MAX).to_string(), "0x1.ffcp+15"); + assert_eq!(Hex(f16::MIN).to_string(), "-0x1.ffcp+15"); + assert_eq!(Hex(f16::ZERO).to_string(), "0x0p+0"); + assert_eq!(Hex(f16::NEG_ZERO).to_string(), "-0x0p+0"); + assert_eq!(Hex(f16::NAN).to_string(), "qNaN"); + assert_eq!(Hex(f16::SNAN).to_string(), "sNaN"); + assert_eq!(Hex(f16::NEG_NAN).to_string(), "-qNaN"); + assert_eq!(Hex(f16::INFINITY).to_string(), "inf"); + assert_eq!(Hex(f16::NEG_INFINITY).to_string(), "-inf"); } #[cfg(f128_enabled)] { assert_eq!( - Hexf(f128::MAX).to_string(), + Hex(f128::MAX).to_string(), "0x1.ffffffffffffffffffffffffffffp+16383" ); assert_eq!( - Hexf(f128::MIN).to_string(), + Hex(f128::MIN).to_string(), "-0x1.ffffffffffffffffffffffffffffp+16383" ); - assert_eq!(Hexf(f128::ZERO).to_string(), "0x0p+0"); - assert_eq!(Hexf(f128::NEG_ZERO).to_string(), "-0x0p+0"); - assert_eq!(Hexf(f128::NAN).to_string(), "qNaN"); - assert_eq!(Hexf(f128::SNAN).to_string(), "sNaN"); - assert_eq!(Hexf(f128::NEG_NAN).to_string(), "-qNaN"); - assert_eq!(Hexf(f128::INFINITY).to_string(), "inf"); - assert_eq!(Hexf(f128::NEG_INFINITY).to_string(), "-inf"); + assert_eq!(Hex(f128::ZERO).to_string(), "0x0p+0"); + assert_eq!(Hex(f128::NEG_ZERO).to_string(), "-0x0p+0"); + assert_eq!(Hex(f128::NAN).to_string(), "qNaN"); + assert_eq!(Hex(f128::SNAN).to_string(), "sNaN"); + assert_eq!(Hex(f128::NEG_NAN).to_string(), "-qNaN"); + assert_eq!(Hex(f128::INFINITY).to_string(), "inf"); + assert_eq!(Hex(f128::NEG_INFINITY).to_string(), "-inf"); } } } diff --git a/library/compiler-builtins/libm/src/math/support/int_traits.rs b/library/compiler-builtins/libm/src/math/support/int_traits.rs index 55b609affd2e6..f113f9d62d143 100644 --- a/library/compiler-builtins/libm/src/math/support/int_traits.rs +++ b/library/compiler-builtins/libm/src/math/support/int_traits.rs @@ -3,6 +3,8 @@ use core::{cmp, fmt, ops}; mod narrowing_div; pub use narrowing_div::NarrowingDiv; +use crate::support::DisplayHex; + /// Minimal integer implementations needed on all integer types, including wide integers. #[allow(dead_code)] // Some constants are only used with tests pub trait MinInt: @@ -40,6 +42,7 @@ pub trait Int: + fmt::Display + fmt::Binary + fmt::LowerHex + + DisplayHex + ops::AddAssign + ops::SubAssign + ops::MulAssign diff --git a/library/compiler-builtins/libm/src/math/support/macros.rs b/library/compiler-builtins/libm/src/math/support/macros.rs index 550d2e92eb7c5..0b6cdfab66e26 100644 --- a/library/compiler-builtins/libm/src/math/support/macros.rs +++ b/library/compiler-builtins/libm/src/math/support/macros.rs @@ -146,9 +146,9 @@ macro_rules! assert_biteq { "{}\nl: {l:?} ({lb:#0width$x} {lh})\nr: {r:?} ({rb:#0width$x} {rh})", format_args!($($tt)*), lb = l.to_bits(), - lh = $crate::support::Hexf(l), + lh = $crate::support::Hex(l), rb = r.to_bits(), - rh = $crate::support::Hexf(r), + rh = $crate::support::Hex(r), width = ((bits / 4) + 2) as usize, ); diff --git a/library/compiler-builtins/libm/src/math/support/mod.rs b/library/compiler-builtins/libm/src/math/support/mod.rs index 9dc872cdc1506..b8269fc212ce0 100644 --- a/library/compiler-builtins/libm/src/math/support/mod.rs +++ b/library/compiler-builtins/libm/src/math/support/mod.rs @@ -19,8 +19,6 @@ pub use env::{FpResult, Round, Status}; #[allow(unused_imports)] pub use float_traits::{DFloat, Float, HFloat, IntTy}; pub(crate) use float_traits::{f32_from_bits, f64_from_bits}; -#[cfg(any(test, feature = "unstable-public-internals"))] -pub use hex_float::Hexf; #[cfg(f16_enabled)] #[allow(unused_imports)] pub use hex_float::hf16; @@ -28,7 +26,7 @@ pub use hex_float::hf16; #[allow(unused_imports)] pub use hex_float::hf128; #[allow(unused_imports)] -pub use hex_float::{hf32, hf64}; +pub use hex_float::{DisplayHex, Hex, hf32, hf64}; pub use int_traits::{CastFrom, CastInto, DInt, HInt, Int, MinInt, NarrowingDiv}; pub use modular::linear_mul_reduction; From f4df517593e905a29ee1bcc0f58631be15001b34 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Tue, 24 Mar 2026 00:58:40 -0500 Subject: [PATCH 024/183] test: Strip multiple suffixes when computing the base name This allows us to use a single base name for functions that have multiple types in the signature, such as `extend_f32_f64`. The compiler-builtins `trunc` operation wrappers had to be renamed to `narrow` to avoid conflicting with libm `trunc`. --- .../crates/libm-macros/src/lib.rs | 37 ++++++++++++++----- .../crates/libm-macros/src/shared.rs | 12 +++--- .../libm-test/benches/icount.rs | 12 +++--- .../libm-test/src/builtins_wrapper.rs | 13 ++++--- .../compiler-builtins/libm-test/src/domain.rs | 8 +--- .../libm-test/src/generate/case_list.rs | 12 +++--- .../libm-test/src/mpfloat.rs | 14 +++---- .../libm-test/src/precision.rs | 7 +--- 8 files changed, 62 insertions(+), 53 deletions(-) diff --git a/library/compiler-builtins/crates/libm-macros/src/lib.rs b/library/compiler-builtins/crates/libm-macros/src/lib.rs index 89333b4b19388..ab1858578e0f9 100644 --- a/library/compiler-builtins/crates/libm-macros/src/lib.rs +++ b/library/compiler-builtins/crates/libm-macros/src/lib.rs @@ -487,7 +487,7 @@ impl VisitMut for MacroReplace { /// Return the unsuffixed version of a function name; e.g. `abs` and `absf` both return `abs`, /// `lgamma_r` and `lgammaf_r` both return `lgamma_r`. fn base_name(name: &str) -> &str { - let known_mappings = &[ + let known_mappings = [ ("erff", "erf"), ("erf", "erf"), ("lgammaf_r", "lgamma_r"), @@ -495,16 +495,33 @@ fn base_name(name: &str) -> &str { ("modf", "modf"), ]; - match known_mappings.iter().find(|known| known.0 == name) { - Some(found) => found.1, - None => name - .strip_suffix("f") - .or_else(|| name.strip_suffix("f16")) - .or_else(|| name.strip_suffix("f32")) - .or_else(|| name.strip_suffix("f64")) - .or_else(|| name.strip_suffix("f128")) - .unwrap_or(name), + if let Some(found) = known_mappings.iter().find(|known| known.0 == name) { + return found.1; } + + // Attempt to strip unambiguous suffixes first. This is repeated so e.g. + // `extend_f32_f64` turns into `extend`. + let strip = [ + "_f16", "_f32", "_f64", "_f128", "_i32", "_i64", "_i128", "_u32", "_u64", "_u128", "f16", + "f32", "f64", "f128", + ]; + + let mut any_found = false; + let mut ret = name; + + for sfx in strip { + if let Some(stripped) = ret.strip_suffix(sfx) { + ret = stripped; + any_found = true; + } + } + + // Only if no suffix was stripped, try stripping the C-style float suffix. + if !any_found && let Some(stripped) = ret.strip_suffix("f") { + ret = stripped; + } + + ret } impl ToTokens for Ty { diff --git a/library/compiler-builtins/crates/libm-macros/src/shared.rs b/library/compiler-builtins/crates/libm-macros/src/shared.rs index d1d79897f399c..7315f5e845a79 100644 --- a/library/compiler-builtins/crates/libm-macros/src/shared.rs +++ b/library/compiler-builtins/crates/libm-macros/src/shared.rs @@ -237,7 +237,7 @@ const ALL_OPERATIONS_NESTED: &[NestedOp] = &[ returns: &[Ty::F16], }, c_sig: None, - fn_list: &["trunc_f32_f16"], + fn_list: &["narrow_f32_f16"], scope: OpScope::BuiltinsPublic, }, NestedOp { @@ -247,7 +247,7 @@ const ALL_OPERATIONS_NESTED: &[NestedOp] = &[ returns: &[Ty::F16], }, c_sig: None, - fn_list: &["trunc_f64_f16"], + fn_list: &["narrow_f64_f16"], scope: OpScope::BuiltinsPublic, }, NestedOp { @@ -257,7 +257,7 @@ const ALL_OPERATIONS_NESTED: &[NestedOp] = &[ returns: &[Ty::F16], }, c_sig: None, - fn_list: &["trunc_f128_f16"], + fn_list: &["narrow_f128_f16"], scope: OpScope::BuiltinsPublic, }, NestedOp { @@ -267,7 +267,7 @@ const ALL_OPERATIONS_NESTED: &[NestedOp] = &[ returns: &[Ty::F32], }, c_sig: None, - fn_list: &["trunc_f64_f32"], + fn_list: &["narrow_f64_f32"], scope: OpScope::BuiltinsPublic, }, NestedOp { @@ -277,7 +277,7 @@ const ALL_OPERATIONS_NESTED: &[NestedOp] = &[ returns: &[Ty::F32], }, c_sig: None, - fn_list: &["trunc_f128_f32"], + fn_list: &["narrow_f128_f32"], scope: OpScope::BuiltinsPublic, }, NestedOp { @@ -287,7 +287,7 @@ const ALL_OPERATIONS_NESTED: &[NestedOp] = &[ returns: &[Ty::F64], }, c_sig: None, - fn_list: &["trunc_f128_f64"], + fn_list: &["narrow_f128_f64"], scope: OpScope::BuiltinsPublic, }, /* libm operations */ diff --git a/library/compiler-builtins/libm-test/benches/icount.rs b/library/compiler-builtins/libm-test/benches/icount.rs index ceec9a21bbf85..294ee9230821a 100644 --- a/library/compiler-builtins/libm-test/benches/icount.rs +++ b/library/compiler-builtins/libm-test/benches/icount.rs @@ -401,6 +401,12 @@ main!( icount_bench_mulf16_group, icount_bench_mulf32_group, icount_bench_mulf64_group, + icount_bench_narrow_f128_f16_group, + icount_bench_narrow_f128_f32_group, + icount_bench_narrow_f128_f64_group, + icount_bench_narrow_f32_f16_group, + icount_bench_narrow_f64_f16_group, + icount_bench_narrow_f64_f32_group, icount_bench_nef128_group, icount_bench_nef16_group, icount_bench_nef32_group, @@ -452,12 +458,6 @@ main!( icount_bench_tanhf_group, icount_bench_tgamma_group, icount_bench_tgammaf_group, - icount_bench_trunc_f128_f16_group, - icount_bench_trunc_f128_f32_group, - icount_bench_trunc_f128_f64_group, - icount_bench_trunc_f32_f16_group, - icount_bench_trunc_f64_f16_group, - icount_bench_trunc_f64_f32_group, icount_bench_trunc_group, icount_bench_truncf128_group, icount_bench_truncf16_group, diff --git a/library/compiler-builtins/libm-test/src/builtins_wrapper.rs b/library/compiler-builtins/libm-test/src/builtins_wrapper.rs index 8da1306a747cd..000982c979e51 100644 --- a/library/compiler-builtins/libm-test/src/builtins_wrapper.rs +++ b/library/compiler-builtins/libm-test/src/builtins_wrapper.rs @@ -148,15 +148,16 @@ cb_op!(extend, __extendsftf2, extend_f32_f128, (a: f32) -> f128); #[cfg(f128_enabled)] cb_op!(extend, __extenddftf2, extend_f64_f128, (a: f64) -> f128); +// Note that these are renamed from trunc to narrow to avoid collision with libm `trunc`. #[cfg(f16_enabled)] -cb_op!(trunc, __truncsfhf2, trunc_f32_f16, (a: f32) -> f16); +cb_op!(trunc, __truncsfhf2, narrow_f32_f16, (a: f32) -> f16); #[cfg(f16_enabled)] -cb_op!(trunc, __truncdfhf2, trunc_f64_f16, (a: f64) -> f16); -cb_op!(trunc, __truncdfsf2, trunc_f64_f32, (a: f64) -> f32); +cb_op!(trunc, __truncdfhf2, narrow_f64_f16, (a: f64) -> f16); +cb_op!(trunc, __truncdfsf2, narrow_f64_f32, (a: f64) -> f32); #[cfg(f16_enabled)] #[cfg(f128_enabled)] -cb_op!(trunc, __trunctfhf2, trunc_f128_f16, (a: f128) -> f16); +cb_op!(trunc, __trunctfhf2, narrow_f128_f16, (a: f128) -> f16); #[cfg(f128_enabled)] -cb_op!(trunc, __trunctfsf2, trunc_f128_f32, (a: f128) -> f32); +cb_op!(trunc, __trunctfsf2, narrow_f128_f32, (a: f128) -> f32); #[cfg(f128_enabled)] -cb_op!(trunc, __trunctfdf2, trunc_f128_f64, (a: f128) -> f64); +cb_op!(trunc, __trunctfdf2, narrow_f128_f64, (a: f128) -> f64); diff --git a/library/compiler-builtins/libm-test/src/domain.rs b/library/compiler-builtins/libm-test/src/domain.rs index 99ecadd891c46..fe7ec261b8f19 100644 --- a/library/compiler-builtins/libm-test/src/domain.rs +++ b/library/compiler-builtins/libm-test/src/domain.rs @@ -241,12 +241,8 @@ pub fn get_domain( BaseName::Unord => &EitherPrim::UNBOUNDED2[..], // Conversions - BaseName::ExtendF16 => &EitherPrim::UNBOUNDED1[..], - BaseName::ExtendF32 => &EitherPrim::UNBOUNDED1[..], - BaseName::ExtendF64 => &EitherPrim::UNBOUNDED1[..], - BaseName::TruncF32 => &EitherPrim::UNBOUNDED1[..], - BaseName::TruncF64 => &EitherPrim::UNBOUNDED1[..], - BaseName::TruncF128 => &EitherPrim::UNBOUNDED1[..], + BaseName::Extend => &EitherPrim::UNBOUNDED1[..], + BaseName::Narrow => &EitherPrim::UNBOUNDED1[..], // Math functions BaseName::Acos => &EitherPrim::INVERSE_TRIG_PERIODIC[..], diff --git a/library/compiler-builtins/libm-test/src/generate/case_list.rs b/library/compiler-builtins/libm-test/src/generate/case_list.rs index 4ce079b62089a..674b76564dba4 100644 --- a/library/compiler-builtins/libm-test/src/generate/case_list.rs +++ b/library/compiler-builtins/libm-test/src/generate/case_list.rs @@ -283,32 +283,32 @@ fn extend_f64_f128_cases() -> Vec> { } #[cfg(f16_enabled)] -fn trunc_f32_f16_cases() -> Vec> { +fn narrow_f32_f16_cases() -> Vec> { vec![] } #[cfg(f16_enabled)] -fn trunc_f64_f16_cases() -> Vec> { +fn narrow_f64_f16_cases() -> Vec> { vec![] } -fn trunc_f64_f32_cases() -> Vec> { +fn narrow_f64_f32_cases() -> Vec> { vec![] } #[cfg(f16_enabled)] #[cfg(f128_enabled)] -fn trunc_f128_f16_cases() -> Vec> { +fn narrow_f128_f16_cases() -> Vec> { vec![] } #[cfg(f128_enabled)] -fn trunc_f128_f32_cases() -> Vec> { +fn narrow_f128_f32_cases() -> Vec> { vec![] } #[cfg(f128_enabled)] -fn trunc_f128_f64_cases() -> Vec> { +fn narrow_f128_f64_cases() -> Vec> { vec![] } diff --git a/library/compiler-builtins/libm-test/src/mpfloat.rs b/library/compiler-builtins/libm-test/src/mpfloat.rs index 677fa2b282307..a313239d7072d 100644 --- a/library/compiler-builtins/libm-test/src/mpfloat.rs +++ b/library/compiler-builtins/libm-test/src/mpfloat.rs @@ -219,6 +219,12 @@ libm_macros::for_each_function! { mulf16, mulf32, mulf64, + narrow_f128_f16, + narrow_f128_f32, + narrow_f128_f64, + narrow_f32_f16, + narrow_f64_f16, + narrow_f64_f32, nef128, nef16, nef32, @@ -253,12 +259,6 @@ libm_macros::for_each_function! { subf32, subf64, trunc, - trunc_f128_f16, - trunc_f128_f32, - trunc_f128_f64, - trunc_f32_f16, - trunc_f64_f16, - trunc_f64_f32, truncf, truncf128, truncf16,yn, @@ -794,7 +794,7 @@ macro_rules! impl_extend_trunc { } } - impl MpOp for crate::op::[]::Routine { + impl MpOp for crate::op::[]::Routine { type MpTy = MpFloat; fn new_mp() -> Self::MpTy { diff --git a/library/compiler-builtins/libm-test/src/precision.rs b/library/compiler-builtins/libm-test/src/precision.rs index b8c257c3edc9f..34d56687a9b9f 100644 --- a/library/compiler-builtins/libm-test/src/precision.rs +++ b/library/compiler-builtins/libm-test/src/precision.rs @@ -27,12 +27,7 @@ pub fn default_ulp(ctx: &CheckCtx) -> Option { Bn::Eq | Bn::Ne | Bn::Gt | Bn::Ge | Bn::Lt | Bn::Le | Bn::Unord | Bn::Ilogb => return None, // Convrsion operations must be precise. - BaseName::ExtendF16 - | BaseName::ExtendF32 - | BaseName::ExtendF64 - | BaseName::TruncF128 - | BaseName::TruncF32 - | BaseName::TruncF64 => 0, + BaseName::Extend | BaseName::Narrow => 0, // Operations that require exact results. This list should correlate with what we // have documented at . From 4303aa93503f10edda4740d3115d0d94ad22185d Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Tue, 24 Mar 2026 00:39:00 -0500 Subject: [PATCH 025/183] test: Cover compiler-builtins float to int conversion in libm-test Add the following to the test infrastructure: * `__fixdfdi` * `__fixdfsi` * `__fixdfti` * `__fixsfdi` * `__fixsfsi` * `__fixsfti` * `__fixtfdi` * `__fixtfsi` * `__fixtfti` * `__fixunsdfdi` * `__fixunsdfsi` * `__fixunsdfti` * `__fixunssfdi` * `__fixunssfsi` * `__fixunssfti` * `__fixunstfdi` * `__fixunstfsi` * `__fixunstfti` --- .../crates/libm-macros/src/lib.rs | 5 + .../crates/libm-macros/src/shared.rs | 198 +++++++++++++++++- .../libm-test/src/builtins_wrapper.rs | 25 +++ .../compiler-builtins/libm-test/src/domain.rs | 1 + .../libm-test/src/generate/case_list.rs | 78 +++++++ .../libm-test/src/mpfloat.rs | 76 ++++++- .../libm-test/src/precision.rs | 2 +- 7 files changed, 380 insertions(+), 5 deletions(-) diff --git a/library/compiler-builtins/crates/libm-macros/src/lib.rs b/library/compiler-builtins/crates/libm-macros/src/lib.rs index ab1858578e0f9..54afeca9f1bfe 100644 --- a/library/compiler-builtins/crates/libm-macros/src/lib.rs +++ b/library/compiler-builtins/crates/libm-macros/src/lib.rs @@ -532,6 +532,11 @@ impl ToTokens for Ty { Ty::F64 => quote! { f64 }, Ty::F128 => quote! { f128 }, Ty::I32 => quote! { i32 }, + Ty::I64 => quote! { i64 }, + Ty::I128 => quote! { i128 }, + Ty::U32 => quote! { u32 }, + Ty::U64 => quote! { u64 }, + Ty::U128 => quote! { u128 }, Ty::Bool => quote! { bool }, Ty::CInt => quote! { ::core::ffi::c_int }, Ty::MutF16 => quote! { &'a mut f16 }, diff --git a/library/compiler-builtins/crates/libm-macros/src/shared.rs b/library/compiler-builtins/crates/libm-macros/src/shared.rs index 7315f5e845a79..99d3870fffe25 100644 --- a/library/compiler-builtins/crates/libm-macros/src/shared.rs +++ b/library/compiler-builtins/crates/libm-macros/src/shared.rs @@ -45,7 +45,9 @@ impl OpScope { /// We need a flat list to work with most of the time, but define things as a more convenient /// nested list. const ALL_OPERATIONS_NESTED: &[NestedOp] = &[ - /* compiler-builtins operations */ + /******************************** + * compiler-builtins operations * + ********************************/ NestedOp { float_ty: FloatTy::F16, rust_sig: Signature { @@ -290,7 +292,189 @@ const ALL_OPERATIONS_NESTED: &[NestedOp] = &[ fn_list: &["narrow_f128_f64"], scope: OpScope::BuiltinsPublic, }, - /* libm operations */ + NestedOp { + float_ty: FloatTy::F32, + rust_sig: Signature { + args: &[Ty::F32], + returns: &[Ty::I32], + }, + c_sig: None, + fn_list: &["ftoi_f32_i32"], + scope: OpScope::BuiltinsPublic, + }, + NestedOp { + float_ty: FloatTy::F32, + rust_sig: Signature { + args: &[Ty::F32], + returns: &[Ty::I64], + }, + c_sig: None, + fn_list: &["ftoi_f32_i64"], + scope: OpScope::BuiltinsPublic, + }, + NestedOp { + float_ty: FloatTy::F32, + rust_sig: Signature { + args: &[Ty::F32], + returns: &[Ty::I128], + }, + c_sig: None, + fn_list: &["ftoi_f32_i128"], + scope: OpScope::BuiltinsPublic, + }, + NestedOp { + float_ty: FloatTy::F64, + rust_sig: Signature { + args: &[Ty::F64], + returns: &[Ty::I32], + }, + c_sig: None, + fn_list: &["ftoi_f64_i32"], + scope: OpScope::BuiltinsPublic, + }, + NestedOp { + float_ty: FloatTy::F64, + rust_sig: Signature { + args: &[Ty::F64], + returns: &[Ty::I64], + }, + c_sig: None, + fn_list: &["ftoi_f64_i64"], + scope: OpScope::BuiltinsPublic, + }, + NestedOp { + float_ty: FloatTy::F64, + rust_sig: Signature { + args: &[Ty::F64], + returns: &[Ty::I128], + }, + c_sig: None, + fn_list: &["ftoi_f64_i128"], + scope: OpScope::BuiltinsPublic, + }, + NestedOp { + float_ty: FloatTy::F128, + rust_sig: Signature { + args: &[Ty::F128], + returns: &[Ty::I32], + }, + c_sig: None, + fn_list: &["ftoi_f128_i32"], + scope: OpScope::BuiltinsPublic, + }, + NestedOp { + float_ty: FloatTy::F128, + rust_sig: Signature { + args: &[Ty::F128], + returns: &[Ty::I64], + }, + c_sig: None, + fn_list: &["ftoi_f128_i64"], + scope: OpScope::BuiltinsPublic, + }, + NestedOp { + float_ty: FloatTy::F128, + rust_sig: Signature { + args: &[Ty::F128], + returns: &[Ty::I128], + }, + c_sig: None, + fn_list: &["ftoi_f128_i128"], + scope: OpScope::BuiltinsPublic, + }, + NestedOp { + float_ty: FloatTy::F32, + rust_sig: Signature { + args: &[Ty::F32], + returns: &[Ty::U32], + }, + c_sig: None, + fn_list: &["ftoi_f32_u32"], + scope: OpScope::BuiltinsPublic, + }, + NestedOp { + float_ty: FloatTy::F32, + rust_sig: Signature { + args: &[Ty::F32], + returns: &[Ty::U64], + }, + c_sig: None, + fn_list: &["ftoi_f32_u64"], + scope: OpScope::BuiltinsPublic, + }, + NestedOp { + float_ty: FloatTy::F32, + rust_sig: Signature { + args: &[Ty::F32], + returns: &[Ty::U128], + }, + c_sig: None, + fn_list: &["ftoi_f32_u128"], + scope: OpScope::BuiltinsPublic, + }, + NestedOp { + float_ty: FloatTy::F64, + rust_sig: Signature { + args: &[Ty::F64], + returns: &[Ty::U32], + }, + c_sig: None, + fn_list: &["ftoi_f64_u32"], + scope: OpScope::BuiltinsPublic, + }, + NestedOp { + float_ty: FloatTy::F64, + rust_sig: Signature { + args: &[Ty::F64], + returns: &[Ty::U64], + }, + c_sig: None, + fn_list: &["ftoi_f64_u64"], + scope: OpScope::BuiltinsPublic, + }, + NestedOp { + float_ty: FloatTy::F64, + rust_sig: Signature { + args: &[Ty::F64], + returns: &[Ty::U128], + }, + c_sig: None, + fn_list: &["ftoi_f64_u128"], + scope: OpScope::BuiltinsPublic, + }, + NestedOp { + float_ty: FloatTy::F128, + rust_sig: Signature { + args: &[Ty::F128], + returns: &[Ty::U32], + }, + c_sig: None, + fn_list: &["ftoi_f128_u32"], + scope: OpScope::BuiltinsPublic, + }, + NestedOp { + float_ty: FloatTy::F128, + rust_sig: Signature { + args: &[Ty::F128], + returns: &[Ty::U64], + }, + c_sig: None, + fn_list: &["ftoi_f128_u64"], + scope: OpScope::BuiltinsPublic, + }, + NestedOp { + float_ty: FloatTy::F128, + rust_sig: Signature { + args: &[Ty::F128], + returns: &[Ty::U128], + }, + c_sig: None, + fn_list: &["ftoi_f128_u128"], + scope: OpScope::BuiltinsPublic, + }, + /******************* + * libm operations * + *******************/ NestedOp { // `fn(f16) -> f16` float_ty: FloatTy::F16, @@ -817,6 +1001,11 @@ pub enum Ty { F64, F128, I32, + I64, + I128, + U32, + U64, + U128, Bool, CInt, MutF16, @@ -845,6 +1034,11 @@ impl fmt::Display for Ty { Ty::F64 => "f64", Ty::F128 => "f128", Ty::I32 => "i32", + Ty::I64 => "i64", + Ty::I128 => "i128", + Ty::U32 => "u32", + Ty::U64 => "u64", + Ty::U128 => "u128", Ty::Bool => "bool", Ty::CInt => "::core::ffi::c_int", Ty::MutF16 => "&mut f16", diff --git a/library/compiler-builtins/libm-test/src/builtins_wrapper.rs b/library/compiler-builtins/libm-test/src/builtins_wrapper.rs index 000982c979e51..0fae45b9e6b91 100644 --- a/library/compiler-builtins/libm-test/src/builtins_wrapper.rs +++ b/library/compiler-builtins/libm-test/src/builtins_wrapper.rs @@ -161,3 +161,28 @@ cb_op!(trunc, __trunctfhf2, narrow_f128_f16, (a: f128) -> f16); cb_op!(trunc, __trunctfsf2, narrow_f128_f32, (a: f128) -> f32); #[cfg(f128_enabled)] cb_op!(trunc, __trunctfdf2, narrow_f128_f64, (a: f128) -> f64); + +cb_op!(conv, __fixsfsi, ftoi_f32_i32, (a: f32) -> i32); +cb_op!(conv, __fixsfdi, ftoi_f32_i64, (a: f32) -> i64); +cb_op!(conv, __fixsfti, ftoi_f32_i128, (a: f32) -> i128); +cb_op!(conv, __fixdfsi, ftoi_f64_i32, (a: f64) -> i32); +cb_op!(conv, __fixdfdi, ftoi_f64_i64, (a: f64) -> i64); +cb_op!(conv, __fixdfti, ftoi_f64_i128, (a: f64) -> i128); +#[cfg(f128_enabled)] +cb_op!(conv, __fixtfsi, ftoi_f128_i32, (a: f128) -> i32); +#[cfg(f128_enabled)] +cb_op!(conv, __fixtfdi, ftoi_f128_i64, (a: f128) -> i64); +#[cfg(f128_enabled)] +cb_op!(conv, __fixtfti, ftoi_f128_i128, (a: f128) -> i128); +cb_op!(conv, __fixunssfsi, ftoi_f32_u32, (a: f32) -> u32); +cb_op!(conv, __fixunssfdi, ftoi_f32_u64, (a: f32) -> u64); +cb_op!(conv, __fixunssfti, ftoi_f32_u128, (a: f32) -> u128); +cb_op!(conv, __fixunsdfsi, ftoi_f64_u32, (a: f64) -> u32); +cb_op!(conv, __fixunsdfdi, ftoi_f64_u64, (a: f64) -> u64); +cb_op!(conv, __fixunsdfti, ftoi_f64_u128, (a: f64) -> u128); +#[cfg(f128_enabled)] +cb_op!(conv, __fixunstfsi, ftoi_f128_u32, (a: f128) -> u32); +#[cfg(f128_enabled)] +cb_op!(conv, __fixunstfdi, ftoi_f128_u64, (a: f128) -> u64); +#[cfg(f128_enabled)] +cb_op!(conv, __fixunstfti, ftoi_f128_u128, (a: f128) -> u128); diff --git a/library/compiler-builtins/libm-test/src/domain.rs b/library/compiler-builtins/libm-test/src/domain.rs index fe7ec261b8f19..dcbdfc91a88f6 100644 --- a/library/compiler-builtins/libm-test/src/domain.rs +++ b/library/compiler-builtins/libm-test/src/domain.rs @@ -243,6 +243,7 @@ pub fn get_domain( // Conversions BaseName::Extend => &EitherPrim::UNBOUNDED1[..], BaseName::Narrow => &EitherPrim::UNBOUNDED1[..], + BaseName::Ftoi => &EitherPrim::UNBOUNDED1[..], // Math functions BaseName::Acos => &EitherPrim::INVERSE_TRIG_PERIODIC[..], diff --git a/library/compiler-builtins/libm-test/src/generate/case_list.rs b/library/compiler-builtins/libm-test/src/generate/case_list.rs index 674b76564dba4..f04d3cc01dda1 100644 --- a/library/compiler-builtins/libm-test/src/generate/case_list.rs +++ b/library/compiler-builtins/libm-test/src/generate/case_list.rs @@ -312,6 +312,84 @@ fn narrow_f128_f64_cases() -> Vec> { vec![] } +fn ftoi_f32_i32_cases() -> Vec> { + vec![] +} + +fn ftoi_f32_i64_cases() -> Vec> { + vec![] +} + +fn ftoi_f32_i128_cases() -> Vec> { + vec![] +} + +fn ftoi_f64_i32_cases() -> Vec> { + vec![] +} + +fn ftoi_f64_i64_cases() -> Vec> { + vec![] +} + +fn ftoi_f64_i128_cases() -> Vec> { + vec![] +} + +#[cfg(f128_enabled)] +fn ftoi_f128_i32_cases() -> Vec> { + vec![] +} + +#[cfg(f128_enabled)] +fn ftoi_f128_i64_cases() -> Vec> { + vec![] +} + +#[cfg(f128_enabled)] +fn ftoi_f128_i128_cases() -> Vec> { + vec![] +} + +fn ftoi_f32_u32_cases() -> Vec> { + vec![] +} + +fn ftoi_f32_u64_cases() -> Vec> { + vec![] +} + +fn ftoi_f32_u128_cases() -> Vec> { + vec![] +} + +fn ftoi_f64_u32_cases() -> Vec> { + vec![] +} + +fn ftoi_f64_u64_cases() -> Vec> { + vec![] +} + +fn ftoi_f64_u128_cases() -> Vec> { + vec![] +} + +#[cfg(f128_enabled)] +fn ftoi_f128_u32_cases() -> Vec> { + vec![] +} + +#[cfg(f128_enabled)] +fn ftoi_f128_u64_cases() -> Vec> { + vec![] +} + +#[cfg(f128_enabled)] +fn ftoi_f128_u128_cases() -> Vec> { + vec![] +} + /******************* * libm test cases * *******************/ diff --git a/library/compiler-builtins/libm-test/src/mpfloat.rs b/library/compiler-builtins/libm-test/src/mpfloat.rs index a313239d7072d..3982c8cf8727a 100644 --- a/library/compiler-builtins/libm-test/src/mpfloat.rs +++ b/library/compiler-builtins/libm-test/src/mpfloat.rs @@ -7,7 +7,7 @@ use std::cmp::Ordering; use rug::Assign; pub use rug::Float as MpFloat; -use rug::az::{self, Az}; +use rug::az::{self, Az, CheckedCast}; use rug::float::Round::Nearest; use rug::ops::{ AddAssignRound, DivAssignRound, MulAssignRound, PowAssignRound, RemAssignRound, SubAssignRound, @@ -21,7 +21,7 @@ fn new_mpfloat() -> MpFloat { } /// Set subnormal emulation and convert to a concrete float type. -fn prep_retval(mp: &mut MpFloat, ord: Ordering) -> F +fn prep_retval(mp: &mut MpFloat, ord: Ordering) -> F where for<'a> &'a MpFloat: az::Cast, { @@ -183,6 +183,24 @@ libm_macros::for_each_function! { frexpf, frexpf128, frexpf16, + ftoi_f128_i128, + ftoi_f128_i32, + ftoi_f128_i64, + ftoi_f128_u128, + ftoi_f128_u32, + ftoi_f128_u64, + ftoi_f32_i128, + ftoi_f32_i32, + ftoi_f32_i64, + ftoi_f32_u128, + ftoi_f32_u32, + ftoi_f32_u64, + ftoi_f64_i128, + ftoi_f64_i32, + ftoi_f64_i64, + ftoi_f64_u128, + ftoi_f64_u32, + ftoi_f64_u64, gef128, gef16, gef32, @@ -810,6 +828,35 @@ macro_rules! impl_extend_trunc { }; } +macro_rules! impl_ftoi { + ($fty:ty, $ity:ty) => { + paste::paste! { + impl MpOp for crate::op::[]::Routine { + type MpTy = MpFloat; + + fn new_mp() -> Self::MpTy { + new_mpfloat::() + } + + fn run(this: &mut Self::MpTy, input: Self::RustArgs) -> Self::RustRet { + this.assign(input.0); + this.trunc_mut(); + this.subnormalize_ieee_round(Ordering::Equal, Nearest); + (&*this).checked_cast().unwrap_or_else(|| { + if this.is_nan() { + 0 + } else if this.is_sign_negative() { + Self::RustRet::MIN + } else { + Self::RustRet::MAX + } + }) + } + } + } + }; +} + impl_op_for_ty!(f32, "f"); impl_op_for_ty!(f64, ""); @@ -838,6 +885,31 @@ impl_extend_trunc!(f32, f128); #[cfg(f128_enabled)] impl_extend_trunc!(f64, f128); +impl_ftoi!(f32, i32); +impl_ftoi!(f32, i64); +impl_ftoi!(f32, i128); +impl_ftoi!(f32, u32); +impl_ftoi!(f32, u64); +impl_ftoi!(f32, u128); +impl_ftoi!(f64, i32); +impl_ftoi!(f64, i64); +impl_ftoi!(f64, i128); +impl_ftoi!(f64, u32); +impl_ftoi!(f64, u64); +impl_ftoi!(f64, u128); +#[cfg(f128_enabled)] +impl_ftoi!(f128, i32); +#[cfg(f128_enabled)] +impl_ftoi!(f128, i64); +#[cfg(f128_enabled)] +impl_ftoi!(f128, i128); +#[cfg(f128_enabled)] +impl_ftoi!(f128, u32); +#[cfg(f128_enabled)] +impl_ftoi!(f128, u64); +#[cfg(f128_enabled)] +impl_ftoi!(f128, u128); + // `lgamma_r` is not a simple suffix so we can't use the above macro. impl MpOp for crate::op::lgamma_r::Routine { type MpTy = MpFloat; diff --git a/library/compiler-builtins/libm-test/src/precision.rs b/library/compiler-builtins/libm-test/src/precision.rs index 34d56687a9b9f..da87df49bf52c 100644 --- a/library/compiler-builtins/libm-test/src/precision.rs +++ b/library/compiler-builtins/libm-test/src/precision.rs @@ -27,7 +27,7 @@ pub fn default_ulp(ctx: &CheckCtx) -> Option { Bn::Eq | Bn::Ne | Bn::Gt | Bn::Ge | Bn::Lt | Bn::Le | Bn::Unord | Bn::Ilogb => return None, // Convrsion operations must be precise. - BaseName::Extend | BaseName::Narrow => 0, + BaseName::Extend | BaseName::Narrow | BaseName::Ftoi => 0, // Operations that require exact results. This list should correlate with what we // have documented at . From 90bb1f20b8e024538359ff29d2b9893a041a1a73 Mon Sep 17 00:00:00 2001 From: Bo YU Date: Tue, 24 Mar 2026 10:55:13 +0000 Subject: [PATCH 026/183] ci: use CARGO_TARGET_DIR instead of .dockerenv for nextest config The .dockerenv check was a workaround for Docker CI where the checkout is mounted read-only. However, its presence does not reliably indicate that the filesystem is unwritable. Use CARGO_TARGET_DIR as the condition instead, which directly captures when a custom writable target directory is in use and avoids false assumptions. --- library/compiler-builtins/ci/run.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/ci/run.sh b/library/compiler-builtins/ci/run.sh index b9a21d555c9e5..766dbb91c598e 100755 --- a/library/compiler-builtins/ci/run.sh +++ b/library/compiler-builtins/ci/run.sh @@ -166,7 +166,7 @@ else cmd=(cargo nextest run --max-fail=10) # Workaround for https://github.com/nextest-rs/nextest/issues/2066 - if [ -f /.dockerenv ]; then + if [ -n "${CARGO_TARGET_DIR:-}" ]; then cfg_file="/tmp/nextest-config.toml" echo "[store]" >> "$cfg_file" echo "dir = \"$CARGO_TARGET_DIR/nextest\"" >> "$cfg_file" From 0adf2b3b24ae88f36fd8edbf1283bce2e666e9ac Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Tue, 24 Mar 2026 01:58:57 -0500 Subject: [PATCH 027/183] test: Move the `math_op` function out of macro code There isn't anything special about its implementation, so make it normal code to clean some things up. --- .../crates/libm-macros/src/enums.rs | 5 ----- .../crates/libm-macros/tests/enum.rs | 13 ------------- library/compiler-builtins/libm-test/src/op.rs | 10 ++++++++++ 3 files changed, 10 insertions(+), 18 deletions(-) diff --git a/library/compiler-builtins/crates/libm-macros/src/enums.rs b/library/compiler-builtins/crates/libm-macros/src/enums.rs index b4646f984d471..f15bdaa63821a 100644 --- a/library/compiler-builtins/crates/libm-macros/src/enums.rs +++ b/library/compiler-builtins/crates/libm-macros/src/enums.rs @@ -93,11 +93,6 @@ pub fn function_enum( #( #base_arms, )* } } - - /// Return information about this operation. - pub fn math_op(self) -> &'static crate::op::MathOpInfo { - crate::op::ALL_OPERATIONS.iter().find(|op| op.name == self.as_str()).unwrap() - } } }; diff --git a/library/compiler-builtins/crates/libm-macros/tests/enum.rs b/library/compiler-builtins/crates/libm-macros/tests/enum.rs index 93e209a0dcc90..f012e0a9ef0ad 100644 --- a/library/compiler-builtins/crates/libm-macros/tests/enum.rs +++ b/library/compiler-builtins/crates/libm-macros/tests/enum.rs @@ -23,16 +23,3 @@ fn basename() { assert_eq!(Identifier::Sin.base_name(), BaseName::Sin); assert_eq!(Identifier::Sinf.base_name(), BaseName::Sin); } - -#[test] -fn math_op() { - assert_eq!(Identifier::Sin.math_op().float_ty, FloatTy::F64); - assert_eq!(Identifier::Sinf.math_op().float_ty, FloatTy::F32); -} - -// Replicate the structure that we have in `libm-test` -mod op { - include!("../../libm-macros/src/shared.rs"); -} - -use op::FloatTy; diff --git a/library/compiler-builtins/libm-test/src/op.rs b/library/compiler-builtins/libm-test/src/op.rs index b88b2f8f94f61..efc6f2998e7cf 100644 --- a/library/compiler-builtins/libm-test/src/op.rs +++ b/library/compiler-builtins/libm-test/src/op.rs @@ -29,6 +29,16 @@ mod shared { #[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] pub enum Identifier {} +impl Identifier { + /// Return information about this operation. + pub fn math_op(self) -> &'static MathOpInfo { + ALL_OPERATIONS + .iter() + .find(|op| op.name == self.as_str()) + .unwrap() + } +} + impl fmt::Display for Identifier { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.write_str(self.as_str()) From 383ddd118dc4913c57e8f750a9715a54dfb1a651 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Tue, 24 Mar 2026 01:58:57 -0500 Subject: [PATCH 028/183] test: Introduce a helper trait for tuple type access Make it possible to access each argument without relying on `FTy`. --- .../compiler-builtins/libm-test/src/lib.rs | 2 +- library/compiler-builtins/libm-test/src/op.rs | 15 +++++++- .../libm-test/src/test_traits.rs | 34 ++++++++++++++++++- 3 files changed, 48 insertions(+), 3 deletions(-) diff --git a/library/compiler-builtins/libm-test/src/lib.rs b/library/compiler-builtins/libm-test/src/lib.rs index 6ba34567af3be..b75f35e6a0058 100644 --- a/library/compiler-builtins/libm-test/src/lib.rs +++ b/library/compiler-builtins/libm-test/src/lib.rs @@ -35,7 +35,7 @@ pub use run_cfg::{ CheckBasis, CheckCtx, EXTENSIVE_ENV, GeneratorKind, bigint_fuzz_iteration_count, skip_extensive_test, }; -pub use test_traits::{CheckOutput, TupleCall}; +pub use test_traits::{CheckOutput, Tuple, TupleCall}; /// Result type for tests is usually from `anyhow`. Most times there is no success value to /// propagate. diff --git a/library/compiler-builtins/libm-test/src/op.rs b/library/compiler-builtins/libm-test/src/op.rs index efc6f2998e7cf..452e1693c216d 100644 --- a/library/compiler-builtins/libm-test/src/op.rs +++ b/library/compiler-builtins/libm-test/src/op.rs @@ -18,7 +18,7 @@ use std::panic::{RefUnwindSafe, UnwindSafe}; pub use shared::{ALL_OPERATIONS, FloatTy, MathOpInfo, Ty}; -use crate::{CheckOutput, Float, TupleCall}; +use crate::{CheckOutput, Float, Tuple, TupleCall}; mod shared { include!("../../crates/libm-macros/src/shared.rs"); @@ -82,6 +82,7 @@ pub trait MathOp { /// The required `TupleCall` bounds ensure this type can be passed either to the C function or /// to the Rust function. type RustArgs: Copy + + Tuple + TupleCall + TupleCall + RefUnwindSafe; @@ -117,6 +118,18 @@ pub type OpRustArgs = ::RustArgs; /// Access the associated `RustRet` type from an op (helper to avoid ambiguous associated types). pub type OpRustRet = ::RustRet; +/// Get the type of the first Rust argument. +pub type Arg0 = as Tuple>::T0; +/// Get the type of the second Rust argument. +pub type Arg1 = as Tuple>::T1; +/// Get the type of the third Rust argument. +pub type Arg2 = as Tuple>::T2; + +/// If the Rust return type is a tuple, get the first type. +pub type Ret0 = as Tuple>::T0; +/// If the Rust return type is a tuple, get the second type. +pub type Ret1 = as Tuple>::T1; + macro_rules! create_op_modules { // Matcher for unary functions ( diff --git a/library/compiler-builtins/libm-test/src/test_traits.rs b/library/compiler-builtins/libm-test/src/test_traits.rs index 811de8f2ab453..1f0baf701bd02 100644 --- a/library/compiler-builtins/libm-test/src/test_traits.rs +++ b/library/compiler-builtins/libm-test/src/test_traits.rs @@ -1,7 +1,8 @@ //! Traits related to testing. //! -//! There are two main traits in this module: +//! There are three main traits in this module: //! +//! - `Tuple`: Implemented on tuples to help extract types. //! - `TupleCall`: implemented on tuples to allow calling them as function arguments. //! - `CheckOutput`: implemented on anything that is an output type for validation against an //! expected value. @@ -23,6 +24,7 @@ use crate::{ /// tuple for multiple signatures). pub trait TupleCall: fmt::Debug { type Output; + fn call(self, f: Func) -> Self::Output; /// Intercept panics and print the input to stderr before continuing. @@ -42,6 +44,16 @@ pub trait TupleCall: fmt::Debug { } } +/// Helper to allow extracting types from a tuple. +pub trait Tuple { + type T0; + type T1; + type T2; +} + +/// If a tuple contains fewer types than provided in `Tuple`, they use this struct. +pub enum Unused {} + /// A trait to implement on any output type so we can verify it in a generic way. pub trait CheckOutput: Sized { /// Validate `self` (actual) and `expected` are the same. @@ -50,6 +62,26 @@ pub trait CheckOutput: Sized { fn validate(self, expected: Self, input: Input, ctx: &CheckCtx) -> TestResult; } +/* implement Tuple */ + +impl Tuple for (T0,) { + type T0 = T0; + type T1 = Unused; + type T2 = Unused; +} + +impl Tuple for (T0, T1) { + type T0 = T0; + type T1 = T1; + type T2 = Unused; +} + +impl Tuple for (T0, T1, T2) { + type T0 = T0; + type T1 = T1; + type T2 = T2; +} + /* implement `TupleCall` */ impl TupleCall R> for (T1,) From 495d1e84ec914cadb2cddacf9be1c78f20db0d90 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Tue, 24 Mar 2026 01:58:57 -0500 Subject: [PATCH 029/183] test: Migrate from using `FTy` to accessing individual arguments We can always access individual arguments rather than relying on the common `FTy` type. This is a cleaner design anyway since it handles functions with integers in the signature better. --- .../libm-test/src/generate/edge_cases.rs | 79 +++++++------- .../libm-test/src/generate/spaced.rs | 55 +++++----- .../compiler-builtins/libm-test/src/lib.rs | 4 +- .../libm-test/src/mpfloat.rs | 102 +++++++++--------- 4 files changed, 118 insertions(+), 122 deletions(-) diff --git a/library/compiler-builtins/libm-test/src/generate/edge_cases.rs b/library/compiler-builtins/libm-test/src/generate/edge_cases.rs index 4e4a782a16988..6d261e06f380e 100644 --- a/library/compiler-builtins/libm-test/src/generate/edge_cases.rs +++ b/library/compiler-builtins/libm-test/src/generate/edge_cases.rs @@ -4,9 +4,8 @@ use libm::support::{CastInto, Float, Int, MinInt}; use crate::domain::get_domain; use crate::generate::KnownSize; -use crate::op::OpITy; use crate::run_cfg::{check_near_count, check_point_count}; -use crate::{BaseName, CheckCtx, FloatExt, FloatTy, MathOp, test_log}; +use crate::{Arg0, Arg1, Arg2, BaseName, CheckCtx, FloatExt, MathOp, Ty, test_log}; /// Generate a sequence of edge cases, e.g. numbers near zeroes and infiniteis. pub trait EdgeCaseInput { @@ -14,15 +13,12 @@ pub trait EdgeCaseInput { } /// Create a list of values around interesting points (infinities, zeroes, NaNs). -fn float_edge_cases( +fn float_edge_cases( ctx: &CheckCtx, argnum: usize, -) -> (impl Iterator + Clone, u64) -where - Op: MathOp, -{ +) -> (impl Iterator + Clone, u64) { let mut ret = Vec::new(); - let one = OpITy::::ONE; + let one = F::Int::ONE; let values = &mut ret; let domain = get_domain::<_, i8>(ctx.fn_ident, argnum).unwrap_float(); let domain_start = domain.range_start(); @@ -32,17 +28,17 @@ where let near_points = check_near_count(ctx); // Check near some notable constants - count_up(Op::FTy::ONE, near_points, values); - count_up(Op::FTy::ZERO, near_points, values); - count_up(Op::FTy::NEG_ONE, near_points, values); - count_down(Op::FTy::ONE, near_points, values); - count_down(Op::FTy::ZERO, near_points, values); - count_down(Op::FTy::NEG_ONE, near_points, values); - values.push(Op::FTy::NEG_ZERO); + count_up(F::ONE, near_points, values); + count_up(F::ZERO, near_points, values); + count_up(F::NEG_ONE, near_points, values); + count_down(F::ONE, near_points, values); + count_down(F::ZERO, near_points, values); + count_down(F::NEG_ONE, near_points, values); + values.push(F::NEG_ZERO); // Check values near the extremes - count_up(Op::FTy::NEG_INFINITY, near_points, values); - count_down(Op::FTy::INFINITY, near_points, values); + count_up(F::NEG_INFINITY, near_points, values); + count_down(F::INFINITY, near_points, values); count_down(domain_end, near_points, values); count_up(domain_start, near_points, values); count_down(domain_start, near_points, values); @@ -50,20 +46,20 @@ where count_down(domain_end, near_points, values); // Check some special values that aren't included in the above ranges - values.push(Op::FTy::NAN); - values.push(Op::FTy::NEG_NAN); - values.extend(Op::FTy::consts().iter()); + values.push(F::NAN); + values.push(F::NEG_NAN); + values.extend(F::consts().iter()); // Check around the maximum subnormal value - let sub_max = Op::FTy::from_bits(Op::FTy::SIG_MASK); + let sub_max = F::from_bits(F::SIG_MASK); count_up(sub_max, near_points, values); count_down(sub_max, near_points, values); count_up(-sub_max, near_points, values); count_down(-sub_max, near_points, values); // Check a few values around the subnormal range - for shift in (0..Op::FTy::SIG_BITS).step_by(Op::FTy::SIG_BITS as usize / 5) { - let v = Op::FTy::from_bits(one << shift); + for shift in (0..F::SIG_BITS).step_by(F::SIG_BITS as usize / 5) { + let v = F::from_bits(one << shift); count_up(v, 2, values); count_down(v, 2, values); count_up(-v, 2, values); @@ -142,21 +138,22 @@ where if matches!(ctx.base_name, BaseName::Scalbn | BaseName::Ldexp) { assert_eq!(argnum, 1, "scalbn integer argument should be arg1"); - let (emax, emin, emin_sn) = match ctx.fn_ident.math_op().float_ty { - FloatTy::F16 => { + let (emax, emin, emin_sn) = match ctx.fn_ident.math_op().rust_sig.args[0] { + Ty::F16 => { #[cfg(not(f16_enabled))] unreachable!(); #[cfg(f16_enabled)] (f16::EXP_MAX, f16::EXP_MIN, f16::EXP_MIN_SUBNORM) } - FloatTy::F32 => (f32::EXP_MAX, f32::EXP_MIN, f32::EXP_MIN_SUBNORM), - FloatTy::F64 => (f64::EXP_MAX, f64::EXP_MIN, f64::EXP_MIN_SUBNORM), - FloatTy::F128 => { + Ty::F32 => (f32::EXP_MAX, f32::EXP_MIN, f32::EXP_MIN_SUBNORM), + Ty::F64 => (f64::EXP_MAX, f64::EXP_MIN, f64::EXP_MIN_SUBNORM), + Ty::F128 => { #[cfg(not(f128_enabled))] unreachable!(); #[cfg(f128_enabled)] (f128::EXP_MAX, f128::EXP_MIN, f128::EXP_MIN_SUBNORM) } + ty => unreachable!("expected a float first argument, got {ty}"), }; // `scalbn`/`ldexp` have their trickiest behavior around exponent limits @@ -213,10 +210,10 @@ macro_rules! impl_edge_case_input { ($fty:ty) => { impl EdgeCaseInput for ($fty,) where - Op: MathOp, + Op: MathOp, { fn get_cases(ctx: &CheckCtx) -> (impl Iterator, u64) { - let (iter0, steps0) = float_edge_cases::(ctx, 0); + let (iter0, steps0) = float_edge_cases::>(ctx, 0); let iter0 = iter0.map(|v| (v,)); (iter0, steps0) } @@ -224,11 +221,11 @@ macro_rules! impl_edge_case_input { impl EdgeCaseInput for ($fty, $fty) where - Op: MathOp, + Op: MathOp, { fn get_cases(ctx: &CheckCtx) -> (impl Iterator, u64) { - let (iter0, steps0) = float_edge_cases::(ctx, 0); - let (iter1, steps1) = float_edge_cases::(ctx, 1); + let (iter0, steps0) = float_edge_cases::>(ctx, 0); + let (iter1, steps1) = float_edge_cases::>(ctx, 1); let iter = iter0.flat_map(move |first| iter1.clone().map(move |second| (first, second))); let count = steps0.checked_mul(steps1).unwrap(); @@ -238,12 +235,12 @@ macro_rules! impl_edge_case_input { impl EdgeCaseInput for ($fty, $fty, $fty) where - Op: MathOp, + Op: MathOp, { fn get_cases(ctx: &CheckCtx) -> (impl Iterator, u64) { - let (iter0, steps0) = float_edge_cases::(ctx, 0); - let (iter1, steps1) = float_edge_cases::(ctx, 1); - let (iter2, steps2) = float_edge_cases::(ctx, 2); + let (iter0, steps0) = float_edge_cases::>(ctx, 0); + let (iter1, steps1) = float_edge_cases::>(ctx, 1); + let (iter2, steps2) = float_edge_cases::>(ctx, 2); let iter = iter0 .flat_map(move |first| iter1.clone().map(move |second| (first, second))) @@ -262,11 +259,11 @@ macro_rules! impl_edge_case_input { impl EdgeCaseInput for (i32, $fty) where - Op: MathOp, + Op: MathOp, { fn get_cases(ctx: &CheckCtx) -> (impl Iterator, u64) { let (iter0, steps0) = int_edge_cases(ctx, 0); - let (iter1, steps1) = float_edge_cases::(ctx, 1); + let (iter1, steps1) = float_edge_cases::>(ctx, 1); let iter = iter0.flat_map(move |first| iter1.clone().map(move |second| (first, second))); @@ -278,10 +275,10 @@ macro_rules! impl_edge_case_input { impl EdgeCaseInput for ($fty, i32) where - Op: MathOp, + Op: MathOp, { fn get_cases(ctx: &CheckCtx) -> (impl Iterator, u64) { - let (iter0, steps0) = float_edge_cases::(ctx, 0); + let (iter0, steps0) = float_edge_cases::>(ctx, 0); let (iter1, steps1) = int_edge_cases(ctx, 1); let iter = diff --git a/library/compiler-builtins/libm-test/src/generate/spaced.rs b/library/compiler-builtins/libm-test/src/generate/spaced.rs index 8e6b376ebd1e9..0a31f232ee301 100644 --- a/library/compiler-builtins/libm-test/src/generate/spaced.rs +++ b/library/compiler-builtins/libm-test/src/generate/spaced.rs @@ -4,9 +4,8 @@ use std::ops::RangeInclusive; use libm::support::{Float, MinInt}; use crate::domain::get_domain; -use crate::op::OpITy; use crate::run_cfg::{int_range, iteration_count}; -use crate::{CheckCtx, MathOp, linear_ints, logspace}; +use crate::{Arg0, Arg1, Arg2, CheckCtx, MathOp, linear_ints, logspace}; /// Generate a sequence of inputs that eiher cover the domain in completeness (for smaller float /// types and single argument functions) or provide evenly spaced inputs across the domain with @@ -17,23 +16,23 @@ pub trait SpacedInput { /// Construct an iterator from `logspace` and also calculate the total number of steps expected /// for that iterator. -fn logspace_steps( +fn logspace_steps( ctx: &CheckCtx, argnum: usize, max_steps: u64, -) -> (impl Iterator + Clone, u64) +) -> (impl Iterator + Clone, u64) where - Op: MathOp, - OpITy: TryFrom, - u64: TryFrom, Error: fmt::Debug>, - RangeInclusive>: Iterator, + F: Float, + F::Int: TryFrom, + u64: TryFrom, + RangeInclusive: Iterator, { // i8 is a dummy type here, it can be any integer. - let domain = get_domain::(ctx.fn_ident, argnum).unwrap_float(); + let domain = get_domain::(ctx.fn_ident, argnum).unwrap_float(); let start = domain.range_start(); let end = domain.range_end(); - let max_steps = OpITy::::try_from(max_steps).unwrap_or(OpITy::::MAX); + let max_steps = F::Int::try_from(max_steps).unwrap_or(F::Int::MAX); let (iter, steps) = logspace(start, end, max_steps); // `steps` will be <= the original `max_steps`, which is a `u64`. @@ -87,19 +86,19 @@ macro_rules! impl_spaced_input { ($fty:ty) => { impl SpacedInput for ($fty,) where - Op: MathOp, + Op: MathOp, { fn get_cases(ctx: &CheckCtx) -> (impl Iterator, u64) { let max_steps0 = iteration_count(ctx, 0); // `f16` and `f32` can have exhaustive tests. - match value_count::() { + match value_count::>() { Some(steps0) if steps0 <= max_steps0 => { let iter0 = all_values(); let iter0 = iter0.map(|v| (v,)); (EitherIter::A(iter0), steps0) } _ => { - let (iter0, steps0) = logspace_steps::(ctx, 0, max_steps0); + let (iter0, steps0) = logspace_steps::>(ctx, 0, max_steps0); let iter0 = iter0.map(|v| (v,)); (EitherIter::B(iter0), steps0) } @@ -109,21 +108,21 @@ macro_rules! impl_spaced_input { impl SpacedInput for ($fty, $fty) where - Op: MathOp, + Op: MathOp, { fn get_cases(ctx: &CheckCtx) -> (impl Iterator, u64) { let max_steps0 = iteration_count(ctx, 0); let max_steps1 = iteration_count(ctx, 1); // `f16` can have exhaustive tests. - match value_count::() { + match value_count::>() { Some(count) if count <= max_steps0 && count <= max_steps1 => { let iter = all_values() .flat_map(|first| all_values().map(move |second| (first, second))); (EitherIter::A(iter), count.checked_mul(count).unwrap()) } _ => { - let (iter0, steps0) = logspace_steps::(ctx, 0, max_steps0); - let (iter1, steps1) = logspace_steps::(ctx, 1, max_steps1); + let (iter0, steps0) = logspace_steps::>(ctx, 0, max_steps0); + let (iter1, steps1) = logspace_steps::>(ctx, 1, max_steps1); let iter = iter0.flat_map(move |first| { iter1.clone().map(move |second| (first, second)) }); @@ -136,14 +135,14 @@ macro_rules! impl_spaced_input { impl SpacedInput for ($fty, $fty, $fty) where - Op: MathOp, + Op: MathOp, { fn get_cases(ctx: &CheckCtx) -> (impl Iterator, u64) { let max_steps0 = iteration_count(ctx, 0); let max_steps1 = iteration_count(ctx, 1); let max_steps2 = iteration_count(ctx, 2); // `f16` can be exhaustive tested if `LIBM_EXTENSIVE_TESTS` is incresed. - match value_count::() { + match value_count::>() { Some(count) if count <= max_steps0 && count <= max_steps1 && count <= max_steps2 => { @@ -155,9 +154,9 @@ macro_rules! impl_spaced_input { (EitherIter::A(iter), count.checked_pow(3).unwrap()) } _ => { - let (iter0, steps0) = logspace_steps::(ctx, 0, max_steps0); - let (iter1, steps1) = logspace_steps::(ctx, 1, max_steps1); - let (iter2, steps2) = logspace_steps::(ctx, 2, max_steps2); + let (iter0, steps0) = logspace_steps::>(ctx, 0, max_steps0); + let (iter1, steps1) = logspace_steps::>(ctx, 1, max_steps1); + let (iter2, steps2) = logspace_steps::>(ctx, 2, max_steps2); let iter = iter0 .flat_map(move |first| iter1.clone().map(move |second| (first, second))) @@ -178,13 +177,13 @@ macro_rules! impl_spaced_input { impl SpacedInput for (i32, $fty) where - Op: MathOp, + Op: MathOp, { fn get_cases(ctx: &CheckCtx) -> (impl Iterator, u64) { let range0 = int_range(ctx, 0); let max_steps0 = iteration_count(ctx, 0); let max_steps1 = iteration_count(ctx, 1); - match value_count::() { + match value_count::>() { Some(count1) if count1 <= max_steps1 => { let (iter0, steps0) = linear_ints(range0, max_steps0); let iter = iter0 @@ -193,7 +192,7 @@ macro_rules! impl_spaced_input { } _ => { let (iter0, steps0) = linear_ints(range0, max_steps0); - let (iter1, steps1) = logspace_steps::(ctx, 1, max_steps1); + let (iter1, steps1) = logspace_steps::>(ctx, 1, max_steps1); let iter = iter0.flat_map(move |first| { iter1.clone().map(move |second| (first, second)) @@ -208,13 +207,13 @@ macro_rules! impl_spaced_input { impl SpacedInput for ($fty, i32) where - Op: MathOp, + Op: MathOp, { fn get_cases(ctx: &CheckCtx) -> (impl Iterator, u64) { let max_steps0 = iteration_count(ctx, 0); let range1 = int_range(ctx, 1); let max_steps1 = iteration_count(ctx, 1); - match value_count::() { + match value_count::>() { Some(count0) if count0 <= max_steps0 => { let (iter1, steps1) = linear_ints(range1, max_steps1); let iter = all_values().flat_map(move |first| { @@ -223,7 +222,7 @@ macro_rules! impl_spaced_input { (EitherIter::A(iter), count0.checked_mul(steps1).unwrap()) } _ => { - let (iter0, steps0) = logspace_steps::(ctx, 0, max_steps0); + let (iter0, steps0) = logspace_steps::>(ctx, 0, max_steps0); let (iter1, steps1) = linear_ints(range1, max_steps1); let iter = iter0.flat_map(move |first| { diff --git a/library/compiler-builtins/libm-test/src/lib.rs b/library/compiler-builtins/libm-test/src/lib.rs index b75f35e6a0058..4d930a7e0ced7 100644 --- a/library/compiler-builtins/libm-test/src/lib.rs +++ b/library/compiler-builtins/libm-test/src/lib.rs @@ -26,8 +26,8 @@ pub use f8_impl::{f8, hf8}; pub use libm::support::{Float, Int, IntTy, MinInt}; pub use num::{FloatExt, linear_ints, logspace}; pub use op::{ - BaseName, FloatTy, Identifier, MathOp, OpCFn, OpCRet, OpFTy, OpRustArgs, OpRustFn, OpRustRet, - Ty, + Arg0, Arg1, Arg2, BaseName, FloatTy, Identifier, MathOp, OpCFn, OpCRet, OpFTy, OpRustArgs, + OpRustFn, OpRustRet, Ret0, Ret1, Ty, }; pub use precision::{MaybeOverride, SpecialCase, default_ulp}; use run_cfg::extensive_max_iterations; diff --git a/library/compiler-builtins/libm-test/src/mpfloat.rs b/library/compiler-builtins/libm-test/src/mpfloat.rs index 3982c8cf8727a..69a9727dd5ed3 100644 --- a/library/compiler-builtins/libm-test/src/mpfloat.rs +++ b/library/compiler-builtins/libm-test/src/mpfloat.rs @@ -13,7 +13,7 @@ use rug::ops::{ AddAssignRound, DivAssignRound, MulAssignRound, PowAssignRound, RemAssignRound, SubAssignRound, }; -use crate::{Float, MathOp}; +use crate::{Arg0, Arg1, Arg2, Float, MathOp, Ret0, Ret1}; /// Create a multiple-precision float with the correct number of bits for a concrete float type. fn new_mpfloat() -> MpFloat { @@ -61,7 +61,7 @@ macro_rules! impl_mp_op { type MpTy = MpFloat; fn new_mp() -> Self::MpTy { - new_mpfloat::() + new_mpfloat::>() } fn run(this: &mut Self::MpTy, input: Self::RustArgs) -> Self::RustRet { @@ -85,7 +85,7 @@ macro_rules! impl_mp_op { type MpTy = (MpFloat, MpFloat); fn new_mp() -> Self::MpTy { - (new_mpfloat::(), new_mpfloat::()) + (new_mpfloat::>(), new_mpfloat::>()) } fn run(this: &mut Self::MpTy, input: Self::RustArgs) -> Self::RustRet { @@ -111,9 +111,9 @@ macro_rules! impl_mp_op { fn new_mp() -> Self::MpTy { ( - new_mpfloat::(), - new_mpfloat::(), - new_mpfloat::(), + new_mpfloat::>(), + new_mpfloat::>(), + new_mpfloat::>(), ) } @@ -318,7 +318,7 @@ macro_rules! impl_no_round { type MpTy = MpFloat; fn new_mp() -> Self::MpTy { - new_mpfloat::() + new_mpfloat::>() } fn run(this: &mut Self::MpTy, input: Self::RustArgs) -> Self::RustRet { @@ -377,7 +377,7 @@ macro_rules! impl_op_for_ty { type MpTy = (MpFloat, MpFloat); fn new_mp() -> Self::MpTy { - (new_mpfloat::(), new_mpfloat::()) + (new_mpfloat::>(), new_mpfloat::>()) } fn run(this: &mut Self::MpTy, input: Self::RustArgs) -> Self::RustRet { @@ -385,8 +385,8 @@ macro_rules! impl_op_for_ty { this.1.assign(&this.0); let (ord0, ord1) = this.0.trunc_fract_round(&mut this.1, Nearest); ( - prep_retval::(&mut this.1, ord0), - prep_retval::(&mut this.0, ord1), + prep_retval::>(&mut this.1, ord0), + prep_retval::>(&mut this.0, ord1), ) } } @@ -395,7 +395,7 @@ macro_rules! impl_op_for_ty { type MpTy = (MpFloat, MpFloat); fn new_mp() -> Self::MpTy { - (new_mpfloat::(), new_mpfloat::()) + (new_mpfloat::>(), new_mpfloat::>()) } fn run(this: &mut Self::MpTy, input: Self::RustArgs) -> Self::RustRet { @@ -410,14 +410,14 @@ macro_rules! impl_op_for_ty { type MpTy = MpFloat; fn new_mp() -> Self::MpTy { - new_mpfloat::() + new_mpfloat::>() } fn run(this: &mut Self::MpTy, input: Self::RustArgs) -> Self::RustRet { let (n, x) = input; this.assign(x); let ord = this.jn_round(n, Nearest); - prep_retval::(this, ord) + prep_retval::(this, ord) } } @@ -425,7 +425,7 @@ macro_rules! impl_op_for_ty { type MpTy = (MpFloat, MpFloat); fn new_mp() -> Self::MpTy { - (new_mpfloat::(), new_mpfloat::()) + (new_mpfloat::>(), new_mpfloat::>()) } fn run(this: &mut Self::MpTy, input: Self::RustArgs) -> Self::RustRet { @@ -433,8 +433,8 @@ macro_rules! impl_op_for_ty { this.1.assign(0.0); let (sord, cord) = this.0.sin_cos_round(&mut this.1, Nearest); ( - prep_retval::(&mut this.0, sord), - prep_retval::(&mut this.1, cord) + prep_retval::>(&mut this.0, sord), + prep_retval::>(&mut this.1, cord) ) } } @@ -444,8 +444,8 @@ macro_rules! impl_op_for_ty { fn new_mp() -> Self::MpTy { ( - new_mpfloat::(), - new_mpfloat::(), + new_mpfloat::>(), + new_mpfloat::>(), ) } @@ -453,7 +453,7 @@ macro_rules! impl_op_for_ty { this.0.assign(input.0); this.1.assign(input.1); let (ord, q) = this.0.remainder_quo31_round(&this.1, Nearest); - (prep_retval::(&mut this.0, ord), q) + (prep_retval::>(&mut this.0, ord), q) } } @@ -461,14 +461,14 @@ macro_rules! impl_op_for_ty { type MpTy = MpFloat; fn new_mp() -> Self::MpTy { - new_mpfloat::() + new_mpfloat::>() } fn run(this: &mut Self::MpTy, input: Self::RustArgs) -> Self::RustRet { let (n, x) = input; this.assign(x); let ord = this.yn_round(n, Nearest); - prep_retval::(this, ord) + prep_retval::(this, ord) } } } @@ -483,7 +483,7 @@ macro_rules! impl_op_for_ty_all { type MpTy = (MpFloat, MpFloat); fn new_mp() -> Self::MpTy { - (new_mpfloat::(), new_mpfloat::()) + (new_mpfloat::>(), new_mpfloat::>()) } fn run(this: &mut Self::MpTy, input: Self::RustArgs) -> Self::RustRet { @@ -498,7 +498,7 @@ macro_rules! impl_op_for_ty_all { type MpTy = (MpFloat, MpFloat); fn new_mp() -> Self::MpTy { - (new_mpfloat::(), new_mpfloat::()) + (new_mpfloat::>(), new_mpfloat::>()) } fn run(this: &mut Self::MpTy, input: Self::RustArgs) -> Self::RustRet { @@ -513,7 +513,7 @@ macro_rules! impl_op_for_ty_all { type MpTy = (MpFloat, MpFloat); fn new_mp() -> Self::MpTy { - (new_mpfloat::(), new_mpfloat::()) + (new_mpfloat::>(), new_mpfloat::>()) } fn run(this: &mut Self::MpTy, input: Self::RustArgs) -> Self::RustRet { @@ -528,7 +528,7 @@ macro_rules! impl_op_for_ty_all { type MpTy = (MpFloat, MpFloat); fn new_mp() -> Self::MpTy { - (new_mpfloat::(), new_mpfloat::()) + (new_mpfloat::>(), new_mpfloat::>()) } fn run(this: &mut Self::MpTy, input: Self::RustArgs) -> Self::RustRet { @@ -542,7 +542,7 @@ macro_rules! impl_op_for_ty_all { type MpTy = (MpFloat, MpFloat); fn new_mp() -> Self::MpTy { - (new_mpfloat::(), new_mpfloat::()) + (new_mpfloat::>(), new_mpfloat::>()) } fn run(this: &mut Self::MpTy, input: Self::RustArgs) -> Self::RustRet { @@ -556,7 +556,7 @@ macro_rules! impl_op_for_ty_all { type MpTy = (MpFloat, MpFloat); fn new_mp() -> Self::MpTy { - (new_mpfloat::(), new_mpfloat::()) + (new_mpfloat::>(), new_mpfloat::>()) } fn run(this: &mut Self::MpTy, input: Self::RustArgs) -> Self::RustRet { @@ -570,7 +570,7 @@ macro_rules! impl_op_for_ty_all { type MpTy = (MpFloat, MpFloat); fn new_mp() -> Self::MpTy { - (new_mpfloat::(), new_mpfloat::()) + (new_mpfloat::>(), new_mpfloat::>()) } fn run(this: &mut Self::MpTy, input: Self::RustArgs) -> Self::RustRet { @@ -584,7 +584,7 @@ macro_rules! impl_op_for_ty_all { type MpTy = (MpFloat, MpFloat); fn new_mp() -> Self::MpTy { - (new_mpfloat::(), new_mpfloat::()) + (new_mpfloat::>(), new_mpfloat::>()) } fn run(this: &mut Self::MpTy, input: Self::RustArgs) -> Self::RustRet { @@ -598,7 +598,7 @@ macro_rules! impl_op_for_ty_all { type MpTy = (MpFloat, MpFloat); fn new_mp() -> Self::MpTy { - (new_mpfloat::(), new_mpfloat::()) + (new_mpfloat::>(), new_mpfloat::>()) } fn run(this: &mut Self::MpTy, input: Self::RustArgs) -> Self::RustRet { @@ -612,7 +612,7 @@ macro_rules! impl_op_for_ty_all { type MpTy = (MpFloat, MpFloat); fn new_mp() -> Self::MpTy { - (new_mpfloat::(), new_mpfloat::()) + (new_mpfloat::>(), new_mpfloat::>()) } fn run(this: &mut Self::MpTy, input: Self::RustArgs) -> Self::RustRet { @@ -626,7 +626,7 @@ macro_rules! impl_op_for_ty_all { type MpTy = (MpFloat, MpFloat); fn new_mp() -> Self::MpTy { - (new_mpfloat::(), new_mpfloat::()) + (new_mpfloat::>(), new_mpfloat::>()) } fn run(this: &mut Self::MpTy, input: Self::RustArgs) -> Self::RustRet { @@ -641,7 +641,7 @@ macro_rules! impl_op_for_ty_all { type MpTy = (MpFloat, MpFloat); fn new_mp() -> Self::MpTy { - (new_mpfloat::(), new_mpfloat::()) + (new_mpfloat::>(), new_mpfloat::>()) } fn run(this: &mut Self::MpTy, input: Self::RustArgs) -> Self::RustRet { @@ -657,7 +657,7 @@ macro_rules! impl_op_for_ty_all { type MpTy = (MpFloat, MpFloat); fn new_mp() -> Self::MpTy { - (new_mpfloat::(), new_mpfloat::()) + (new_mpfloat::>(), new_mpfloat::>()) } fn run(this: &mut Self::MpTy, input: Self::RustArgs) -> Self::RustRet { @@ -677,7 +677,7 @@ macro_rules! impl_op_for_ty_all { type MpTy = (MpFloat, MpFloat); fn new_mp() -> Self::MpTy { - (new_mpfloat::(), new_mpfloat::()) + (new_mpfloat::>(), new_mpfloat::>()) } fn run(this: &mut Self::MpTy, input: Self::RustArgs) -> Self::RustRet { @@ -697,13 +697,13 @@ macro_rules! impl_op_for_ty_all { type MpTy = MpFloat; fn new_mp() -> Self::MpTy { - new_mpfloat::() + new_mpfloat::>() } fn run(this: &mut Self::MpTy, input: Self::RustArgs) -> Self::RustRet { this.assign(input.0); let exp = this.frexp_mut(); - (prep_retval::(this, Ordering::Equal), exp) + (prep_retval::>(this, Ordering::Equal), exp) } } @@ -711,7 +711,7 @@ macro_rules! impl_op_for_ty_all { type MpTy = MpFloat; fn new_mp() -> Self::MpTy { - new_mpfloat::() + new_mpfloat::>() } fn run(this: &mut Self::MpTy, input: Self::RustArgs) -> Self::RustRet { @@ -748,13 +748,13 @@ macro_rules! impl_op_for_ty_all { type MpTy = MpFloat; fn new_mp() -> Self::MpTy { - new_mpfloat::() + new_mpfloat::>() } fn run(this: &mut Self::MpTy, input: Self::RustArgs) -> Self::RustRet { this.assign(input.0); *this <<= input.1; - prep_retval::(this, Ordering::Equal) + prep_retval::(this, Ordering::Equal) } } } @@ -768,7 +768,7 @@ macro_rules! impl_op_for_ty_no_f16 { type MpTy = (MpFloat, MpFloat); fn new_mp() -> Self::MpTy { - (new_mpfloat::(), new_mpfloat::()) + (new_mpfloat::>(), new_mpfloat::>()) } fn run(this: &mut Self::MpTy, input: Self::RustArgs) -> Self::RustRet { @@ -783,7 +783,7 @@ macro_rules! impl_op_for_ty_no_f16 { type MpTy = MpFloat; fn new_mp() -> Self::MpTy { - new_mpfloat::() + new_mpfloat::>() } fn run(this: &mut Self::MpTy, input: Self::RustArgs) -> Self::RustRet { @@ -803,7 +803,7 @@ macro_rules! impl_extend_trunc { type MpTy = MpFloat; fn new_mp() -> Self::MpTy { - new_mpfloat::() + new_mpfloat::>() } fn run(this: &mut Self::MpTy, input: Self::RustArgs) -> Self::RustRet { @@ -816,7 +816,7 @@ macro_rules! impl_extend_trunc { type MpTy = MpFloat; fn new_mp() -> Self::MpTy { - new_mpfloat::() + new_mpfloat::>() } fn run(this: &mut Self::MpTy, input: Self::RustArgs) -> Self::RustRet { @@ -835,7 +835,7 @@ macro_rules! impl_ftoi { type MpTy = MpFloat; fn new_mp() -> Self::MpTy { - new_mpfloat::() + new_mpfloat::>() } fn run(this: &mut Self::MpTy, input: Self::RustArgs) -> Self::RustRet { @@ -915,13 +915,13 @@ impl MpOp for crate::op::lgamma_r::Routine { type MpTy = MpFloat; fn new_mp() -> Self::MpTy { - new_mpfloat::() + new_mpfloat::>() } fn run(this: &mut Self::MpTy, input: Self::RustArgs) -> Self::RustRet { this.assign(input.0); let (sign, ord) = this.ln_abs_gamma_round(Nearest); - let ret = prep_retval::(this, ord); + let ret = prep_retval::>(this, ord); (ret, sign as i32) } } @@ -930,13 +930,13 @@ impl MpOp for crate::op::lgammaf_r::Routine { type MpTy = MpFloat; fn new_mp() -> Self::MpTy { - new_mpfloat::() + new_mpfloat::>() } fn run(this: &mut Self::MpTy, input: Self::RustArgs) -> Self::RustRet { this.assign(input.0); let (sign, ord) = this.ln_abs_gamma_round(Nearest); - let ret = prep_retval::(this, ord); + let ret = prep_retval::>(this, ord); (ret, sign as i32) } } @@ -945,7 +945,7 @@ impl MpOp for crate::op::lgamma::Routine { type MpTy = MpFloat; fn new_mp() -> Self::MpTy { - new_mpfloat::() + new_mpfloat::>() } fn run(this: &mut Self::MpTy, input: Self::RustArgs) -> Self::RustRet { @@ -957,7 +957,7 @@ impl MpOp for crate::op::lgammaf::Routine { type MpTy = MpFloat; fn new_mp() -> Self::MpTy { - new_mpfloat::() + new_mpfloat::>() } fn run(this: &mut Self::MpTy, input: Self::RustArgs) -> Self::RustRet { From d713b422f1570890538ce043654bd4374a6fec31 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Tue, 24 Mar 2026 01:58:57 -0500 Subject: [PATCH 030/183] test: Remove `FTy` from `libm-test` traits Now that tests have moved to using argument types instead of a whole- function float type, remove `FTy` and its relevant configuration. This will make it possible to use the same infrastructure for functions that don't have any floats as arguments, or don't have any at all. Some uses of `FTy` have been replaced with the `Group` enum, e.g. for match arm patterns and selecting extensive tests. Anything that doesn't have float types in the signature will be in the `Integer` category. --- .../crates/libm-macros/src/lib.rs | 36 ++-- .../crates/libm-macros/src/shared.rs | 167 ++++++++---------- .../crates/libm-macros/tests/basic.rs | 2 - .../libm-test/examples/plot_domains.rs | 2 +- .../compiler-builtins/libm-test/src/lib.rs | 4 +- library/compiler-builtins/libm-test/src/op.rs | 25 +-- .../libm-test/src/run_cfg.rs | 40 +++-- 7 files changed, 125 insertions(+), 151 deletions(-) diff --git a/library/compiler-builtins/crates/libm-macros/src/lib.rs b/library/compiler-builtins/crates/libm-macros/src/lib.rs index 54afeca9f1bfe..acb7edf704374 100644 --- a/library/compiler-builtins/crates/libm-macros/src/lib.rs +++ b/library/compiler-builtins/crates/libm-macros/src/lib.rs @@ -6,13 +6,14 @@ use parse::{Invocation, StructuredInput}; use proc_macro as pm; use proc_macro2::{self as pm2, Span}; use quote::{ToTokens, quote}; -pub(crate) use shared::{ALL_OPERATIONS, FloatTy, MathOpInfo, Ty}; +use shared::Group; +pub(crate) use shared::{ALL_OPERATIONS, MathOpInfo, Ty}; use syn::spanned::Spanned; use syn::visit_mut::VisitMut; use syn::{Ident, ItemEnum, PathArguments, PathSegment}; const KNOWN_TYPES: &[&str] = &[ - "FTy", "CFn", "CArgs", "CRet", "RustFn", "RustArgs", "RustRet", "path", + "CFn", "CArgs", "CRet", "RustFn", "RustArgs", "RustRet", "path", ]; /// Populate an enum with a variant representing function. Names are in upper camel case. @@ -66,8 +67,6 @@ pub fn base_name_enum(attributes: pm::TokenStream, tokens: pm::TokenStream) -> p /// ( /// // Name of that function /// fn_name: $fn_name:ident, -/// // The basic float type for this function (e.g. `f32`, `f64`) -/// FTy: $FTy:ty, /// // Function signature of the C version (e.g. `fn(f32, &mut f32) -> f32`) /// CFn: $CFn:ty, /// // A tuple representing the C version's arguments (e.g. `(f32, &mut f32)`) @@ -143,11 +142,12 @@ pub fn for_each_function(tokens: pm::TokenStream) -> pm::TokenStream { fn validate(input: &mut StructuredInput) -> syn::Result> { // Replace magic mappers with a list of relevant functions. if let Some(map) = &mut input.fn_extra { - for (name, ty) in [ - ("ALL_F16", FloatTy::F16), - ("ALL_F32", FloatTy::F32), - ("ALL_F64", FloatTy::F64), - ("ALL_F128", FloatTy::F128), + for (name, group) in [ + ("ALL_F16", Group::F16), + ("ALL_F32", Group::F32), + ("ALL_F64", Group::F64), + ("ALL_F128", Group::F128), + ("ALL_INT", Group::Integer), ] { let Some(k) = map.keys().find(|key| *key == name) else { continue; @@ -156,7 +156,7 @@ fn validate(input: &mut StructuredInput) -> syn::Result let key = k.clone(); let val = map.remove(&key).unwrap(); - for op in ALL_OPERATIONS.iter().filter(|op| op.float_ty == ty) { + for op in ALL_OPERATIONS.iter().filter(|op| op.group == group) { map.insert(Ident::new(op.name, key.span()), val.clone()); } } @@ -233,7 +233,7 @@ fn validate(input: &mut StructuredInput) -> syn::Result // Omit f16 and f128 functions if requested if input.skip_f16_f128 { - if matches!(func.float_ty, FloatTy::F16 | FloatTy::F128) { + if matches!(func.group, Group::F16 | Group::F128) { continue; } @@ -383,7 +383,6 @@ fn expand(input: StructuredInput, fn_list: &[&MathOpInfo]) -> syn::Result pm2::TokenStream::new(), }; - let base_fty = func.float_ty; let c_args = &func.c_sig.args; let c_ret = &func.c_sig.returns; let rust_args = &func.rust_sig.args; @@ -403,7 +402,6 @@ fn expand(input: StructuredInput, fn_list: &[&MathOpInfo]) -> syn::Result quote! { FTy: #base_fty, }, "CFn" => quote! { CFn: fn( #(#c_args),* ,) -> ( #(#c_ret),* ), }, "CArgs" => quote! { CArgs: ( #(#c_args),* ,), }, "CRet" => quote! { CRet: ( #(#c_ret),* ), }, @@ -550,15 +548,3 @@ impl ToTokens for Ty { tokens.extend(ts); } } -impl ToTokens for FloatTy { - fn to_tokens(&self, tokens: &mut pm2::TokenStream) { - let ts = match self { - FloatTy::F16 => quote! { f16 }, - FloatTy::F32 => quote! { f32 }, - FloatTy::F64 => quote! { f64 }, - FloatTy::F128 => quote! { f128 }, - }; - - tokens.extend(ts); - } -} diff --git a/library/compiler-builtins/crates/libm-macros/src/shared.rs b/library/compiler-builtins/crates/libm-macros/src/shared.rs index 99d3870fffe25..7571e064ccbee 100644 --- a/library/compiler-builtins/crates/libm-macros/src/shared.rs +++ b/library/compiler-builtins/crates/libm-macros/src/shared.rs @@ -4,8 +4,8 @@ use std::collections::HashSet; use std::fmt; use std::sync::LazyLock; +/// Convenient structure for defining items, gets expanded into a flat structure. struct NestedOp { - float_ty: FloatTy, rust_sig: Signature, c_sig: Option, fn_list: &'static [&'static str], @@ -49,7 +49,6 @@ const ALL_OPERATIONS_NESTED: &[NestedOp] = &[ * compiler-builtins operations * ********************************/ NestedOp { - float_ty: FloatTy::F16, rust_sig: Signature { args: &[Ty::F16, Ty::F16], returns: &[Ty::F16], @@ -59,7 +58,6 @@ const ALL_OPERATIONS_NESTED: &[NestedOp] = &[ scope: OpScope::BuiltinsPublic, }, NestedOp { - float_ty: FloatTy::F32, rust_sig: Signature { args: &[Ty::F32, Ty::F32], returns: &[Ty::F32], @@ -69,7 +67,6 @@ const ALL_OPERATIONS_NESTED: &[NestedOp] = &[ scope: OpScope::BuiltinsPublic, }, NestedOp { - float_ty: FloatTy::F64, rust_sig: Signature { args: &[Ty::F64, Ty::F64], returns: &[Ty::F64], @@ -79,7 +76,6 @@ const ALL_OPERATIONS_NESTED: &[NestedOp] = &[ scope: OpScope::BuiltinsPublic, }, NestedOp { - float_ty: FloatTy::F128, rust_sig: Signature { args: &[Ty::F128, Ty::F128], returns: &[Ty::F128], @@ -89,7 +85,6 @@ const ALL_OPERATIONS_NESTED: &[NestedOp] = &[ scope: OpScope::BuiltinsPublic, }, NestedOp { - float_ty: FloatTy::F32, rust_sig: Signature { args: &[Ty::F32, Ty::I32], returns: &[Ty::F32], @@ -99,7 +94,6 @@ const ALL_OPERATIONS_NESTED: &[NestedOp] = &[ scope: OpScope::BuiltinsPublic, }, NestedOp { - float_ty: FloatTy::F64, rust_sig: Signature { args: &[Ty::F64, Ty::I32], returns: &[Ty::F64], @@ -109,7 +103,6 @@ const ALL_OPERATIONS_NESTED: &[NestedOp] = &[ scope: OpScope::BuiltinsPublic, }, NestedOp { - float_ty: FloatTy::F128, rust_sig: Signature { args: &[Ty::F128, Ty::I32], returns: &[Ty::F128], @@ -119,7 +112,6 @@ const ALL_OPERATIONS_NESTED: &[NestedOp] = &[ scope: OpScope::BuiltinsPublic, }, NestedOp { - float_ty: FloatTy::F16, rust_sig: Signature { args: &[Ty::F16, Ty::F16], returns: &[Ty::Bool], @@ -131,7 +123,6 @@ const ALL_OPERATIONS_NESTED: &[NestedOp] = &[ scope: OpScope::BuiltinsPublic, }, NestedOp { - float_ty: FloatTy::F32, rust_sig: Signature { args: &[Ty::F32, Ty::F32], returns: &[Ty::Bool], @@ -143,7 +134,6 @@ const ALL_OPERATIONS_NESTED: &[NestedOp] = &[ scope: OpScope::BuiltinsPublic, }, NestedOp { - float_ty: FloatTy::F64, rust_sig: Signature { args: &[Ty::F64, Ty::F64], returns: &[Ty::Bool], @@ -155,7 +145,6 @@ const ALL_OPERATIONS_NESTED: &[NestedOp] = &[ scope: OpScope::BuiltinsPublic, }, NestedOp { - float_ty: FloatTy::F128, rust_sig: Signature { args: &[Ty::F128, Ty::F128], returns: &[Ty::Bool], @@ -173,7 +162,6 @@ const ALL_OPERATIONS_NESTED: &[NestedOp] = &[ scope: OpScope::BuiltinsPublic, }, NestedOp { - float_ty: FloatTy::F16, rust_sig: Signature { args: &[Ty::F16], returns: &[Ty::F32], @@ -183,7 +171,6 @@ const ALL_OPERATIONS_NESTED: &[NestedOp] = &[ scope: OpScope::BuiltinsPublic, }, NestedOp { - float_ty: FloatTy::F16, rust_sig: Signature { args: &[Ty::F16], returns: &[Ty::F64], @@ -193,7 +180,6 @@ const ALL_OPERATIONS_NESTED: &[NestedOp] = &[ scope: OpScope::BuiltinsPublic, }, NestedOp { - float_ty: FloatTy::F16, rust_sig: Signature { args: &[Ty::F16], returns: &[Ty::F128], @@ -203,7 +189,6 @@ const ALL_OPERATIONS_NESTED: &[NestedOp] = &[ scope: OpScope::BuiltinsPublic, }, NestedOp { - float_ty: FloatTy::F32, rust_sig: Signature { args: &[Ty::F32], returns: &[Ty::F64], @@ -213,7 +198,6 @@ const ALL_OPERATIONS_NESTED: &[NestedOp] = &[ scope: OpScope::BuiltinsPublic, }, NestedOp { - float_ty: FloatTy::F32, rust_sig: Signature { args: &[Ty::F32], returns: &[Ty::F128], @@ -223,7 +207,6 @@ const ALL_OPERATIONS_NESTED: &[NestedOp] = &[ scope: OpScope::BuiltinsPublic, }, NestedOp { - float_ty: FloatTy::F64, rust_sig: Signature { args: &[Ty::F64], returns: &[Ty::F128], @@ -233,7 +216,6 @@ const ALL_OPERATIONS_NESTED: &[NestedOp] = &[ scope: OpScope::BuiltinsPublic, }, NestedOp { - float_ty: FloatTy::F32, rust_sig: Signature { args: &[Ty::F32], returns: &[Ty::F16], @@ -243,7 +225,6 @@ const ALL_OPERATIONS_NESTED: &[NestedOp] = &[ scope: OpScope::BuiltinsPublic, }, NestedOp { - float_ty: FloatTy::F64, rust_sig: Signature { args: &[Ty::F64], returns: &[Ty::F16], @@ -253,7 +234,6 @@ const ALL_OPERATIONS_NESTED: &[NestedOp] = &[ scope: OpScope::BuiltinsPublic, }, NestedOp { - float_ty: FloatTy::F128, rust_sig: Signature { args: &[Ty::F128], returns: &[Ty::F16], @@ -263,7 +243,6 @@ const ALL_OPERATIONS_NESTED: &[NestedOp] = &[ scope: OpScope::BuiltinsPublic, }, NestedOp { - float_ty: FloatTy::F64, rust_sig: Signature { args: &[Ty::F64], returns: &[Ty::F32], @@ -273,7 +252,6 @@ const ALL_OPERATIONS_NESTED: &[NestedOp] = &[ scope: OpScope::BuiltinsPublic, }, NestedOp { - float_ty: FloatTy::F128, rust_sig: Signature { args: &[Ty::F128], returns: &[Ty::F32], @@ -283,7 +261,6 @@ const ALL_OPERATIONS_NESTED: &[NestedOp] = &[ scope: OpScope::BuiltinsPublic, }, NestedOp { - float_ty: FloatTy::F128, rust_sig: Signature { args: &[Ty::F128], returns: &[Ty::F64], @@ -293,7 +270,6 @@ const ALL_OPERATIONS_NESTED: &[NestedOp] = &[ scope: OpScope::BuiltinsPublic, }, NestedOp { - float_ty: FloatTy::F32, rust_sig: Signature { args: &[Ty::F32], returns: &[Ty::I32], @@ -303,7 +279,6 @@ const ALL_OPERATIONS_NESTED: &[NestedOp] = &[ scope: OpScope::BuiltinsPublic, }, NestedOp { - float_ty: FloatTy::F32, rust_sig: Signature { args: &[Ty::F32], returns: &[Ty::I64], @@ -313,7 +288,6 @@ const ALL_OPERATIONS_NESTED: &[NestedOp] = &[ scope: OpScope::BuiltinsPublic, }, NestedOp { - float_ty: FloatTy::F32, rust_sig: Signature { args: &[Ty::F32], returns: &[Ty::I128], @@ -323,7 +297,6 @@ const ALL_OPERATIONS_NESTED: &[NestedOp] = &[ scope: OpScope::BuiltinsPublic, }, NestedOp { - float_ty: FloatTy::F64, rust_sig: Signature { args: &[Ty::F64], returns: &[Ty::I32], @@ -333,7 +306,6 @@ const ALL_OPERATIONS_NESTED: &[NestedOp] = &[ scope: OpScope::BuiltinsPublic, }, NestedOp { - float_ty: FloatTy::F64, rust_sig: Signature { args: &[Ty::F64], returns: &[Ty::I64], @@ -343,7 +315,6 @@ const ALL_OPERATIONS_NESTED: &[NestedOp] = &[ scope: OpScope::BuiltinsPublic, }, NestedOp { - float_ty: FloatTy::F64, rust_sig: Signature { args: &[Ty::F64], returns: &[Ty::I128], @@ -353,7 +324,6 @@ const ALL_OPERATIONS_NESTED: &[NestedOp] = &[ scope: OpScope::BuiltinsPublic, }, NestedOp { - float_ty: FloatTy::F128, rust_sig: Signature { args: &[Ty::F128], returns: &[Ty::I32], @@ -363,7 +333,6 @@ const ALL_OPERATIONS_NESTED: &[NestedOp] = &[ scope: OpScope::BuiltinsPublic, }, NestedOp { - float_ty: FloatTy::F128, rust_sig: Signature { args: &[Ty::F128], returns: &[Ty::I64], @@ -373,7 +342,6 @@ const ALL_OPERATIONS_NESTED: &[NestedOp] = &[ scope: OpScope::BuiltinsPublic, }, NestedOp { - float_ty: FloatTy::F128, rust_sig: Signature { args: &[Ty::F128], returns: &[Ty::I128], @@ -383,7 +351,6 @@ const ALL_OPERATIONS_NESTED: &[NestedOp] = &[ scope: OpScope::BuiltinsPublic, }, NestedOp { - float_ty: FloatTy::F32, rust_sig: Signature { args: &[Ty::F32], returns: &[Ty::U32], @@ -393,7 +360,6 @@ const ALL_OPERATIONS_NESTED: &[NestedOp] = &[ scope: OpScope::BuiltinsPublic, }, NestedOp { - float_ty: FloatTy::F32, rust_sig: Signature { args: &[Ty::F32], returns: &[Ty::U64], @@ -403,7 +369,6 @@ const ALL_OPERATIONS_NESTED: &[NestedOp] = &[ scope: OpScope::BuiltinsPublic, }, NestedOp { - float_ty: FloatTy::F32, rust_sig: Signature { args: &[Ty::F32], returns: &[Ty::U128], @@ -413,7 +378,6 @@ const ALL_OPERATIONS_NESTED: &[NestedOp] = &[ scope: OpScope::BuiltinsPublic, }, NestedOp { - float_ty: FloatTy::F64, rust_sig: Signature { args: &[Ty::F64], returns: &[Ty::U32], @@ -423,7 +387,6 @@ const ALL_OPERATIONS_NESTED: &[NestedOp] = &[ scope: OpScope::BuiltinsPublic, }, NestedOp { - float_ty: FloatTy::F64, rust_sig: Signature { args: &[Ty::F64], returns: &[Ty::U64], @@ -433,7 +396,6 @@ const ALL_OPERATIONS_NESTED: &[NestedOp] = &[ scope: OpScope::BuiltinsPublic, }, NestedOp { - float_ty: FloatTy::F64, rust_sig: Signature { args: &[Ty::F64], returns: &[Ty::U128], @@ -443,7 +405,6 @@ const ALL_OPERATIONS_NESTED: &[NestedOp] = &[ scope: OpScope::BuiltinsPublic, }, NestedOp { - float_ty: FloatTy::F128, rust_sig: Signature { args: &[Ty::F128], returns: &[Ty::U32], @@ -453,7 +414,6 @@ const ALL_OPERATIONS_NESTED: &[NestedOp] = &[ scope: OpScope::BuiltinsPublic, }, NestedOp { - float_ty: FloatTy::F128, rust_sig: Signature { args: &[Ty::F128], returns: &[Ty::U64], @@ -463,7 +423,6 @@ const ALL_OPERATIONS_NESTED: &[NestedOp] = &[ scope: OpScope::BuiltinsPublic, }, NestedOp { - float_ty: FloatTy::F128, rust_sig: Signature { args: &[Ty::F128], returns: &[Ty::U128], @@ -477,7 +436,6 @@ const ALL_OPERATIONS_NESTED: &[NestedOp] = &[ *******************/ NestedOp { // `fn(f16) -> f16` - float_ty: FloatTy::F16, rust_sig: Signature { args: &[Ty::F16], returns: &[Ty::F16], @@ -497,7 +455,6 @@ const ALL_OPERATIONS_NESTED: &[NestedOp] = &[ }, NestedOp { // `fn(f32) -> f32` - float_ty: FloatTy::F32, rust_sig: Signature { args: &[Ty::F32], returns: &[Ty::F32], @@ -546,7 +503,6 @@ const ALL_OPERATIONS_NESTED: &[NestedOp] = &[ }, NestedOp { // `(f64) -> f64` - float_ty: FloatTy::F64, rust_sig: Signature { args: &[Ty::F64], returns: &[Ty::F64], @@ -595,7 +551,6 @@ const ALL_OPERATIONS_NESTED: &[NestedOp] = &[ }, NestedOp { // `fn(f128) -> f128` - float_ty: FloatTy::F128, rust_sig: Signature { args: &[Ty::F128], returns: &[Ty::F128], @@ -615,7 +570,6 @@ const ALL_OPERATIONS_NESTED: &[NestedOp] = &[ }, NestedOp { // `(f16, f16) -> f16` - float_ty: FloatTy::F16, rust_sig: Signature { args: &[Ty::F16, Ty::F16], returns: &[Ty::F16], @@ -636,7 +590,6 @@ const ALL_OPERATIONS_NESTED: &[NestedOp] = &[ }, NestedOp { // `(f32, f32) -> f32` - float_ty: FloatTy::F32, rust_sig: Signature { args: &[Ty::F32, Ty::F32], returns: &[Ty::F32], @@ -662,7 +615,6 @@ const ALL_OPERATIONS_NESTED: &[NestedOp] = &[ }, NestedOp { // `(f64, f64) -> f64` - float_ty: FloatTy::F64, rust_sig: Signature { args: &[Ty::F64, Ty::F64], returns: &[Ty::F64], @@ -688,7 +640,6 @@ const ALL_OPERATIONS_NESTED: &[NestedOp] = &[ }, NestedOp { // `(f128, f128) -> f128` - float_ty: FloatTy::F128, rust_sig: Signature { args: &[Ty::F128, Ty::F128], returns: &[Ty::F128], @@ -709,7 +660,6 @@ const ALL_OPERATIONS_NESTED: &[NestedOp] = &[ }, NestedOp { // `(f32, f32, f32) -> f32` - float_ty: FloatTy::F32, rust_sig: Signature { args: &[Ty::F32, Ty::F32, Ty::F32], returns: &[Ty::F32], @@ -720,7 +670,6 @@ const ALL_OPERATIONS_NESTED: &[NestedOp] = &[ }, NestedOp { // `(f64, f64, f64) -> f64` - float_ty: FloatTy::F64, rust_sig: Signature { args: &[Ty::F64, Ty::F64, Ty::F64], returns: &[Ty::F64], @@ -731,7 +680,6 @@ const ALL_OPERATIONS_NESTED: &[NestedOp] = &[ }, NestedOp { // `(f128, f128, f128) -> f128` - float_ty: FloatTy::F128, rust_sig: Signature { args: &[Ty::F128, Ty::F128, Ty::F128], returns: &[Ty::F128], @@ -742,7 +690,6 @@ const ALL_OPERATIONS_NESTED: &[NestedOp] = &[ }, NestedOp { // `(f16) -> i32` - float_ty: FloatTy::F16, rust_sig: Signature { args: &[Ty::F16], returns: &[Ty::I32], @@ -753,7 +700,6 @@ const ALL_OPERATIONS_NESTED: &[NestedOp] = &[ }, NestedOp { // `(f32) -> i32` - float_ty: FloatTy::F32, rust_sig: Signature { args: &[Ty::F32], returns: &[Ty::I32], @@ -764,7 +710,6 @@ const ALL_OPERATIONS_NESTED: &[NestedOp] = &[ }, NestedOp { // `(f64) -> i32` - float_ty: FloatTy::F64, rust_sig: Signature { args: &[Ty::F64], returns: &[Ty::I32], @@ -775,7 +720,6 @@ const ALL_OPERATIONS_NESTED: &[NestedOp] = &[ }, NestedOp { // `(f128) -> i32` - float_ty: FloatTy::F128, rust_sig: Signature { args: &[Ty::F128], returns: &[Ty::I32], @@ -786,7 +730,6 @@ const ALL_OPERATIONS_NESTED: &[NestedOp] = &[ }, NestedOp { // `(i32, f32) -> f32` - float_ty: FloatTy::F32, rust_sig: Signature { args: &[Ty::I32, Ty::F32], returns: &[Ty::F32], @@ -797,7 +740,6 @@ const ALL_OPERATIONS_NESTED: &[NestedOp] = &[ }, NestedOp { // `(i32, f64) -> f64` - float_ty: FloatTy::F64, rust_sig: Signature { args: &[Ty::I32, Ty::F64], returns: &[Ty::F64], @@ -808,7 +750,6 @@ const ALL_OPERATIONS_NESTED: &[NestedOp] = &[ }, NestedOp { // `(f16, i32) -> f16` - float_ty: FloatTy::F16, rust_sig: Signature { args: &[Ty::F16, Ty::I32], returns: &[Ty::F16], @@ -819,7 +760,6 @@ const ALL_OPERATIONS_NESTED: &[NestedOp] = &[ }, NestedOp { // `(f32, i32) -> f32` - float_ty: FloatTy::F32, rust_sig: Signature { args: &[Ty::F32, Ty::I32], returns: &[Ty::F32], @@ -830,7 +770,6 @@ const ALL_OPERATIONS_NESTED: &[NestedOp] = &[ }, NestedOp { // `(f64, i64) -> f64` - float_ty: FloatTy::F64, rust_sig: Signature { args: &[Ty::F64, Ty::I32], returns: &[Ty::F64], @@ -841,7 +780,6 @@ const ALL_OPERATIONS_NESTED: &[NestedOp] = &[ }, NestedOp { // `(f128, i32) -> f128` - float_ty: FloatTy::F128, rust_sig: Signature { args: &[Ty::F128, Ty::I32], returns: &[Ty::F128], @@ -852,7 +790,6 @@ const ALL_OPERATIONS_NESTED: &[NestedOp] = &[ }, NestedOp { // `(f32, &mut f32) -> f32` as `(f32) -> (f32, f32)` - float_ty: FloatTy::F32, rust_sig: Signature { args: &[Ty::F32], returns: &[Ty::F32, Ty::F32], @@ -866,7 +803,6 @@ const ALL_OPERATIONS_NESTED: &[NestedOp] = &[ }, NestedOp { // `(f64, &mut f64) -> f64` as `(f64) -> (f64, f64)` - float_ty: FloatTy::F64, rust_sig: Signature { args: &[Ty::F64], returns: &[Ty::F64, Ty::F64], @@ -880,7 +816,6 @@ const ALL_OPERATIONS_NESTED: &[NestedOp] = &[ }, NestedOp { // `(f16, &mut c_int) -> f16` as `(f16) -> (f16, i32)` - float_ty: FloatTy::F16, rust_sig: Signature { args: &[Ty::F16], returns: &[Ty::F16, Ty::I32], @@ -894,7 +829,6 @@ const ALL_OPERATIONS_NESTED: &[NestedOp] = &[ }, NestedOp { // `(f32, &mut c_int) -> f32` as `(f32) -> (f32, i32)` - float_ty: FloatTy::F32, rust_sig: Signature { args: &[Ty::F32], returns: &[Ty::F32, Ty::I32], @@ -908,7 +842,6 @@ const ALL_OPERATIONS_NESTED: &[NestedOp] = &[ }, NestedOp { // `(f64, &mut c_int) -> f64` as `(f64) -> (f64, i32)` - float_ty: FloatTy::F64, rust_sig: Signature { args: &[Ty::F64], returns: &[Ty::F64, Ty::I32], @@ -922,7 +855,6 @@ const ALL_OPERATIONS_NESTED: &[NestedOp] = &[ }, NestedOp { // `(f128, &mut c_int) -> f128` as `(f128) -> (f128, i32)` - float_ty: FloatTy::F128, rust_sig: Signature { args: &[Ty::F128], returns: &[Ty::F128, Ty::I32], @@ -936,7 +868,6 @@ const ALL_OPERATIONS_NESTED: &[NestedOp] = &[ }, NestedOp { // `(f32, f32, &mut c_int) -> f32` as `(f32, f32) -> (f32, i32)` - float_ty: FloatTy::F32, rust_sig: Signature { args: &[Ty::F32, Ty::F32], returns: &[Ty::F32, Ty::I32], @@ -950,7 +881,6 @@ const ALL_OPERATIONS_NESTED: &[NestedOp] = &[ }, NestedOp { // `(f64, f64, &mut c_int) -> f64` as `(f64, f64) -> (f64, i32)` - float_ty: FloatTy::F64, rust_sig: Signature { args: &[Ty::F64, Ty::F64], returns: &[Ty::F64, Ty::I32], @@ -964,7 +894,6 @@ const ALL_OPERATIONS_NESTED: &[NestedOp] = &[ }, NestedOp { // `(f32, &mut f32, &mut f32)` as `(f32) -> (f32, f32)` - float_ty: FloatTy::F32, rust_sig: Signature { args: &[Ty::F32], returns: &[Ty::F32, Ty::F32], @@ -978,7 +907,6 @@ const ALL_OPERATIONS_NESTED: &[NestedOp] = &[ }, NestedOp { // `(f64, &mut f64, &mut f64)` as `(f64) -> (f64, f64)` - float_ty: FloatTy::F64, rust_sig: Signature { args: &[Ty::F64], returns: &[Ty::F64, Ty::F64], @@ -1016,14 +944,75 @@ pub enum Ty { MutCInt, } -/// A subset of [`Ty`] representing only floats. +impl Ty { + /// The number of bits needed to represent this type's possible values. That is, + /// `log2(variant_count)`. + #[allow(dead_code)] + pub fn effective_bits(self) -> u32 { + match self { + Ty::Bool => 1, + Ty::F16 | Ty::MutF16 => 16, + Ty::F32 | Ty::I32 | Ty::U32 | Ty::MutF32 | Ty::MutI32 => 32, + Ty::F64 | Ty::I64 | Ty::U64 | Ty::MutF64 => 64, + Ty::F128 | Ty::I128 | Ty::U128 | Ty::MutF128 => 128, + // Assume we're not testing on a 16-bit system + Ty::CInt | Ty::MutCInt => 32, + } + } + + /// How to group functions that mostly have this kind of input. + fn group(self) -> Group { + match self { + Ty::F16 | Ty::MutF16 => Group::F16, + Ty::F32 | Ty::MutF32 => Group::F32, + Ty::F64 | Ty::MutF64 => Group::F64, + Ty::F128 | Ty::MutF128 => Group::F128, + Ty::I32 + | Ty::I64 + | Ty::I128 + | Ty::U32 + | Ty::U64 + | Ty::U128 + | Ty::Bool + | Ty::CInt + | Ty::MutI32 + | Ty::MutCInt => Group::Integer, + } + } + + fn is_float(self) -> bool { + match self { + Ty::F16 + | Ty::F32 + | Ty::F64 + | Ty::F128 + | Ty::MutF16 + | Ty::MutF32 + | Ty::MutF64 + | Ty::MutF128 => true, + Ty::I32 + | Ty::I64 + | Ty::I128 + | Ty::U32 + | Ty::U64 + | Ty::U128 + | Ty::Bool + | Ty::CInt + | Ty::MutI32 + | Ty::MutCInt => false, + } + } +} + +/// How a function should get grouped for things like extensive tests. #[allow(dead_code)] #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] -pub enum FloatTy { +pub enum Group { F16, F32, F64, F128, + Integer, } impl fmt::Display for Ty { @@ -1052,18 +1041,6 @@ impl fmt::Display for Ty { } } -impl fmt::Display for FloatTy { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - let s = match self { - FloatTy::F16 => "f16", - FloatTy::F32 => "f32", - FloatTy::F64 => "f64", - FloatTy::F128 => "f128", - }; - f.write_str(s) - } -} - /// Representation of e.g. `(f32, f32) -> f32` #[derive(Debug, Clone)] pub struct Signature { @@ -1075,7 +1052,8 @@ pub struct Signature { #[derive(Debug, Clone)] pub struct MathOpInfo { pub name: &'static str, - pub float_ty: FloatTy, + /// How this function should be grouped when needed. Based on the first float argument. + pub group: Group, /// Function signature for C implementations pub c_sig: Signature, /// Function signature for Rust implementations @@ -1093,9 +1071,20 @@ pub static ALL_OPERATIONS: LazyLock> = LazyLock::new(|| { for op in ALL_OPERATIONS_NESTED { let fn_names = op.fn_list; for name in fn_names { + // Locate the first float argument or return value, fall back to whatever the first + // argument is if there are no floats. + let group_ty = op + .rust_sig + .args + .iter() + .chain(op.rust_sig.returns.iter()) + .find(|arg| arg.is_float()) + .unwrap_or(&op.rust_sig.args[0]); + let group = group_ty.group(); + let api = MathOpInfo { name, - float_ty: op.float_ty, + group, rust_sig: op.rust_sig.clone(), c_sig: op.c_sig.clone().unwrap_or_else(|| op.rust_sig.clone()), scope: op.scope, diff --git a/library/compiler-builtins/crates/libm-macros/tests/basic.rs b/library/compiler-builtins/crates/libm-macros/tests/basic.rs index be93bb58e1848..668127c298e47 100644 --- a/library/compiler-builtins/crates/libm-macros/tests/basic.rs +++ b/library/compiler-builtins/crates/libm-macros/tests/basic.rs @@ -7,7 +7,6 @@ macro_rules! basic { ( fn_name: $fn_name:ident, - FTy: $FTy:ty, CFn: $CFn:ty, CArgs: $CArgs:ty, CRet: $CRet:ty, @@ -22,7 +21,6 @@ macro_rules! basic { $(#[$attr])* #[allow(dead_code)] pub mod $fn_name { - type FTy= $FTy; type CFnTy<'a> = $CFn; type RustFnTy = $RustFn; type RustArgsTy = $RustArgs; diff --git a/library/compiler-builtins/libm-test/examples/plot_domains.rs b/library/compiler-builtins/libm-test/examples/plot_domains.rs index 7331d454f2111..b2fd1979ad550 100644 --- a/library/compiler-builtins/libm-test/examples/plot_domains.rs +++ b/library/compiler-builtins/libm-test/examples/plot_domains.rs @@ -52,7 +52,7 @@ fn main() { /// Run multiple generators for a single operator. fn plot_one_operator(out_dir: &Path, config: &mut String) where - Op: MathOp, + Op: MathOp, Op::RustArgs: SpacedInput, { let mut ctx = CheckCtx::new(Op::IDENTIFIER, CheckBasis::Mpfr, GeneratorKind::Spaced); diff --git a/library/compiler-builtins/libm-test/src/lib.rs b/library/compiler-builtins/libm-test/src/lib.rs index 4d930a7e0ced7..f2ee03252139e 100644 --- a/library/compiler-builtins/libm-test/src/lib.rs +++ b/library/compiler-builtins/libm-test/src/lib.rs @@ -26,8 +26,8 @@ pub use f8_impl::{f8, hf8}; pub use libm::support::{Float, Int, IntTy, MinInt}; pub use num::{FloatExt, linear_ints, logspace}; pub use op::{ - Arg0, Arg1, Arg2, BaseName, FloatTy, Identifier, MathOp, OpCFn, OpCRet, OpFTy, OpRustArgs, - OpRustFn, OpRustRet, Ret0, Ret1, Ty, + Arg0, Arg1, Arg2, BaseName, Group, Identifier, MathOp, OpCFn, OpCRet, OpRustArgs, OpRustFn, + OpRustRet, Ret0, Ret1, Ty, }; pub use precision::{MaybeOverride, SpecialCase, default_ulp}; use run_cfg::extensive_max_iterations; diff --git a/library/compiler-builtins/libm-test/src/op.rs b/library/compiler-builtins/libm-test/src/op.rs index 452e1693c216d..14ee67b8d83cc 100644 --- a/library/compiler-builtins/libm-test/src/op.rs +++ b/library/compiler-builtins/libm-test/src/op.rs @@ -16,9 +16,9 @@ use std::fmt; use std::panic::{RefUnwindSafe, UnwindSafe}; -pub use shared::{ALL_OPERATIONS, FloatTy, MathOpInfo, Ty}; +pub use shared::{ALL_OPERATIONS, Group, MathOpInfo, Ty}; -use crate::{CheckOutput, Float, Tuple, TupleCall}; +use crate::{CheckOutput, Tuple, TupleCall}; mod shared { include!("../../crates/libm-macros/src/shared.rs"); @@ -59,9 +59,6 @@ impl fmt::Display for BaseName { /// Attributes ascribed to a `libm` routine including signature, type information, /// and naming. pub trait MathOp { - /// The float type used for this operation. - type FTy: Float; - /// The function type representing the signature in a C library. type CFn: Copy; @@ -103,19 +100,17 @@ pub trait MathOp { const ROUTINE: Self::RustFn; } -/// Access the associated `FTy` type from an op (helper to avoid ambiguous associated types). -pub type OpFTy = ::FTy; -/// Access the associated `FTy::Int` type from an op (helper to avoid ambiguous associated types). -pub type OpITy = <::FTy as Float>::Int; -/// Access the associated `CFn` type from an op (helper to avoid ambiguous associated types). +/* Most of these are workarounds for */ + +/// Access the associated `CFn` type from an op. pub type OpCFn = ::CFn; -/// Access the associated `CRet` type from an op (helper to avoid ambiguous associated types). +/// Access the associated `CRet` type from an op. pub type OpCRet = ::CRet; -/// Access the associated `RustFn` type from an op (helper to avoid ambiguous associated types). +/// Access the associated `RustFn` type from an op. pub type OpRustFn = ::RustFn; -/// Access the associated `RustArgs` type from an op (helper to avoid ambiguous associated types). +/// Access the associated `RustArgs` type from an op. pub type OpRustArgs = ::RustArgs; -/// Access the associated `RustRet` type from an op (helper to avoid ambiguous associated types). +/// Access the associated `RustRet` type from an op. pub type OpRustRet = ::RustRet; /// Get the type of the first Rust argument. @@ -134,7 +129,6 @@ macro_rules! create_op_modules { // Matcher for unary functions ( fn_name: $fn_name:ident, - FTy: $FTy:ty, CFn: $CFn:ty, CArgs: $CArgs:ty, CRet: $CRet:ty, @@ -151,7 +145,6 @@ macro_rules! create_op_modules { pub struct Routine; impl MathOp for Routine { - type FTy = $FTy; type CFn = for<'a> $CFn; type CArgs<'a> = $CArgs where Self: 'a; type CRet = $CRet; diff --git a/library/compiler-builtins/libm-test/src/run_cfg.rs b/library/compiler-builtins/libm-test/src/run_cfg.rs index a8b0a2e117520..b4be30cfc5a60 100644 --- a/library/compiler-builtins/libm-test/src/run_cfg.rs +++ b/library/compiler-builtins/libm-test/src/run_cfg.rs @@ -5,7 +5,7 @@ use std::sync::LazyLock; use std::{env, str}; use crate::generate::random::{SEED, SEED_ENV}; -use crate::{BaseName, FloatTy, Identifier, test_log}; +use crate::{BaseName, Group, Identifier, test_log}; /// The environment variable indicating which extensive tests should be run. pub const EXTENSIVE_ENV: &str = "LIBM_EXTENSIVE_TESTS"; @@ -152,10 +152,10 @@ static EXTENSIVE: LazyLock> = LazyLock::new(|| { let list = var.split(",").filter(|s| !s.is_empty()).collect::>(); let mut ret = Vec::new(); - let append_ty_ops = |ret: &mut Vec<_>, fty: FloatTy| { + let append_ty_ops = |ret: &mut Vec<_>, group: Group| { let iter = Identifier::ALL .iter() - .filter(move |id| id.math_op().float_ty == fty) + .filter(move |id| id.math_op().group == group) .copied(); ret.extend(iter); }; @@ -163,10 +163,11 @@ static EXTENSIVE: LazyLock> = LazyLock::new(|| { for item in list { match item { "all" => ret = Identifier::ALL.to_owned(), - "all_f16" => append_ty_ops(&mut ret, FloatTy::F16), - "all_f32" => append_ty_ops(&mut ret, FloatTy::F32), - "all_f64" => append_ty_ops(&mut ret, FloatTy::F64), - "all_f128" => append_ty_ops(&mut ret, FloatTy::F128), + "all_f16" => append_ty_ops(&mut ret, Group::F16), + "all_f32" => append_ty_ops(&mut ret, Group::F32), + "all_f64" => append_ty_ops(&mut ret, Group::F64), + "all_f128" => append_ty_ops(&mut ret, Group::F128), + "all_int" => append_ty_ops(&mut ret, Group::Integer), s => { let id = Identifier::from_str(s) .unwrap_or_else(|| panic!("unrecognized test name `{s}`")); @@ -178,13 +179,18 @@ static EXTENSIVE: LazyLock> = LazyLock::new(|| { ret }); +/// Most ops are somewhere on the order or 10^7 iterations per second when running exhaustive +/// tests. Assuming about four hours to run, this is log2 of the max number of inputs that coul +/// be tested. +const MAX_REASONABLE_EXHAUSTIVE_BITS: u32 = 36; + /// Information about the function to be tested. #[derive(Debug)] struct TestEnv { /// Tests should be reduced because the platform is slow. E.g. 32-bit or emulated. slow_platform: bool, - /// The float cannot be tested exhaustively, `f64` or `f128`. - large_float_ty: bool, + /// How many bits of input there are for this function. + total_input_bits: u32, /// Env indicates that an extensive test should be run. should_run_extensive: bool, /// Multiprecision tests will be run. @@ -199,10 +205,11 @@ impl TestEnv { let op = id.math_op(); let will_run_mp = cfg!(feature = "build-mpfr"); - let large_float_ty = match op.float_ty { - FloatTy::F16 | FloatTy::F32 => false, - FloatTy::F64 | FloatTy::F128 => true, - }; + + let mut total_input_bits = 0; + for ty in op.rust_sig.args { + total_input_bits += ty.effective_bits(); + } let will_run_extensive = EXTENSIVE.contains(&id); @@ -210,7 +217,7 @@ impl TestEnv { Self { slow_platform: slow_platform(), - large_float_ty, + total_input_bits, should_run_extensive: will_run_extensive, mp_tests_enabled: will_run_mp, input_count, @@ -260,8 +267,9 @@ pub fn iteration_count(ctx: &CheckCtx, argnum: usize) -> u64 { } }; - // Larger float types get more iterations. - if t_env.large_float_ty { + // This signature has too many possible inputs to test exhaustively, so increase input count + // on all other kinds of tests to get better coverage. + if t_env.total_input_bits > MAX_REASONABLE_EXHAUSTIVE_BITS { if ctx.extensive { // Extensive already has a pretty high test count. total_iterations *= 2; From 3135979797fdc45cb8f08c66074e2d49d2623c9f Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Tue, 24 Mar 2026 00:39:00 -0500 Subject: [PATCH 031/183] test: Cover compiler-builtins int to float conversion in libm-test Add the following to the test infrastructure: * `itof_i32_f32` * `itof_i64_f32` * `itof_i128_f32` * `itof_i32_f64` * `itof_i64_f64` * `itof_i128_f64` * `itof_i32_f128` * `itof_i64_f128` * `itof_i128_f128` * `itof_u32_f32` * `itof_u64_f32` * `itof_u128_f32` * `itof_u32_f64` * `itof_u64_f64` * `itof_u128_f64` * `itof_u32_f128` * `itof_u64_f128` * `itof_u128_f128` --- .../crates/libm-macros/src/shared.rs | 164 ++++++++++++++++++ .../compiler-builtins/crates/util/src/main.rs | 32 +++- .../libm-test/src/builtins_wrapper.rs | 25 +++ .../compiler-builtins/libm-test/src/domain.rs | 1 + .../libm-test/src/generate/case_list.rs | 78 +++++++++ .../libm-test/src/generate/edge_cases.rs | 22 +++ .../libm-test/src/generate/random.rs | 35 +++- .../libm-test/src/generate/spaced.rs | 48 ++++- .../libm-test/src/mpfloat.rs | 69 ++++++-- .../compiler-builtins/libm-test/src/num.rs | 27 ++- .../libm-test/src/precision.rs | 9 +- .../libm-test/src/run_cfg.rs | 25 ++- 12 files changed, 485 insertions(+), 50 deletions(-) diff --git a/library/compiler-builtins/crates/libm-macros/src/shared.rs b/library/compiler-builtins/crates/libm-macros/src/shared.rs index 7571e064ccbee..c875068bb2607 100644 --- a/library/compiler-builtins/crates/libm-macros/src/shared.rs +++ b/library/compiler-builtins/crates/libm-macros/src/shared.rs @@ -111,6 +111,7 @@ const ALL_OPERATIONS_NESTED: &[NestedOp] = &[ fn_list: &["powif128"], scope: OpScope::BuiltinsPublic, }, + /* Comparison */ NestedOp { rust_sig: Signature { args: &[Ty::F16, Ty::F16], @@ -161,6 +162,7 @@ const ALL_OPERATIONS_NESTED: &[NestedOp] = &[ ], scope: OpScope::BuiltinsPublic, }, + /* conversion */ NestedOp { rust_sig: Signature { args: &[Ty::F16], @@ -431,6 +433,168 @@ const ALL_OPERATIONS_NESTED: &[NestedOp] = &[ fn_list: &["ftoi_f128_u128"], scope: OpScope::BuiltinsPublic, }, + NestedOp { + rust_sig: Signature { + args: &[Ty::I32], + returns: &[Ty::F32], + }, + c_sig: None, + fn_list: &["itof_i32_f32"], + scope: OpScope::BuiltinsPublic, + }, + NestedOp { + rust_sig: Signature { + args: &[Ty::I64], + returns: &[Ty::F32], + }, + c_sig: None, + fn_list: &["itof_i64_f32"], + scope: OpScope::BuiltinsPublic, + }, + NestedOp { + rust_sig: Signature { + args: &[Ty::I128], + returns: &[Ty::F32], + }, + c_sig: None, + fn_list: &["itof_i128_f32"], + scope: OpScope::BuiltinsPublic, + }, + NestedOp { + rust_sig: Signature { + args: &[Ty::I32], + returns: &[Ty::F64], + }, + c_sig: None, + fn_list: &["itof_i32_f64"], + scope: OpScope::BuiltinsPublic, + }, + NestedOp { + rust_sig: Signature { + args: &[Ty::I64], + returns: &[Ty::F64], + }, + c_sig: None, + fn_list: &["itof_i64_f64"], + scope: OpScope::BuiltinsPublic, + }, + NestedOp { + rust_sig: Signature { + args: &[Ty::I128], + returns: &[Ty::F64], + }, + c_sig: None, + fn_list: &["itof_i128_f64"], + scope: OpScope::BuiltinsPublic, + }, + NestedOp { + rust_sig: Signature { + args: &[Ty::I32], + returns: &[Ty::F128], + }, + c_sig: None, + fn_list: &["itof_i32_f128"], + scope: OpScope::BuiltinsPublic, + }, + NestedOp { + rust_sig: Signature { + args: &[Ty::I64], + returns: &[Ty::F128], + }, + c_sig: None, + fn_list: &["itof_i64_f128"], + scope: OpScope::BuiltinsPublic, + }, + NestedOp { + rust_sig: Signature { + args: &[Ty::I128], + returns: &[Ty::F128], + }, + c_sig: None, + fn_list: &["itof_i128_f128"], + scope: OpScope::BuiltinsPublic, + }, + NestedOp { + rust_sig: Signature { + args: &[Ty::U32], + returns: &[Ty::F32], + }, + c_sig: None, + fn_list: &["itof_u32_f32"], + scope: OpScope::BuiltinsPublic, + }, + NestedOp { + rust_sig: Signature { + args: &[Ty::U64], + returns: &[Ty::F32], + }, + c_sig: None, + fn_list: &["itof_u64_f32"], + scope: OpScope::BuiltinsPublic, + }, + NestedOp { + rust_sig: Signature { + args: &[Ty::U128], + returns: &[Ty::F32], + }, + c_sig: None, + fn_list: &["itof_u128_f32"], + scope: OpScope::BuiltinsPublic, + }, + NestedOp { + rust_sig: Signature { + args: &[Ty::U32], + returns: &[Ty::F64], + }, + c_sig: None, + fn_list: &["itof_u32_f64"], + scope: OpScope::BuiltinsPublic, + }, + NestedOp { + rust_sig: Signature { + args: &[Ty::U64], + returns: &[Ty::F64], + }, + c_sig: None, + fn_list: &["itof_u64_f64"], + scope: OpScope::BuiltinsPublic, + }, + NestedOp { + rust_sig: Signature { + args: &[Ty::U128], + returns: &[Ty::F64], + }, + c_sig: None, + fn_list: &["itof_u128_f64"], + scope: OpScope::BuiltinsPublic, + }, + NestedOp { + rust_sig: Signature { + args: &[Ty::U32], + returns: &[Ty::F128], + }, + c_sig: None, + fn_list: &["itof_u32_f128"], + scope: OpScope::BuiltinsPublic, + }, + NestedOp { + rust_sig: Signature { + args: &[Ty::U64], + returns: &[Ty::F128], + }, + c_sig: None, + fn_list: &["itof_u64_f128"], + scope: OpScope::BuiltinsPublic, + }, + NestedOp { + rust_sig: Signature { + args: &[Ty::U128], + returns: &[Ty::F128], + }, + c_sig: None, + fn_list: &["itof_u128_f128"], + scope: OpScope::BuiltinsPublic, + }, /******************* * libm operations * *******************/ diff --git a/library/compiler-builtins/crates/util/src/main.rs b/library/compiler-builtins/crates/util/src/main.rs index 5be98d8bc0ea4..2810149b2412d 100644 --- a/library/compiler-builtins/crates/util/src/main.rs +++ b/library/compiler-builtins/crates/util/src/main.rs @@ -309,6 +309,31 @@ impl_parse_tuple!(f64); #[cfg(f128_enabled)] impl_parse_tuple_via_rug!(f128); +macro_rules! impl_parse_tuple_int { + ($ty:ty) => { + impl ParseTuple for ($ty,) { + fn parse(input: &[&str]) -> Self { + assert_eq!(input.len(), 1, "expected a single argument, got {input:?}"); + (parse(input, 0),) + } + } + + impl FromStrRadix for $ty { + fn from_str_radix(s: &str, radix: u32) -> Result { + let s = strip_radix_prefix(s, radix); + <$ty>::from_str_radix(s, radix) + } + } + }; +} + +impl_parse_tuple_int!(i32); +impl_parse_tuple_int!(i64); +impl_parse_tuple_int!(i128); +impl_parse_tuple_int!(u32); +impl_parse_tuple_int!(u64); +impl_parse_tuple_int!(u128); + /// Try to parse the number, printing a nice message on failure. fn parse(input: &[&str], idx: usize) -> T { let s = input[idx]; @@ -355,13 +380,6 @@ trait FromStrRadix: Sized { fn from_str_radix(s: &str, radix: u32) -> Result; } -impl FromStrRadix for i32 { - fn from_str_radix(s: &str, radix: u32) -> Result { - let s = strip_radix_prefix(s, radix); - i32::from_str_radix(s, radix) - } -} - #[cfg(f16_enabled)] impl FromStrRadix for f16 { fn from_str_radix(s: &str, radix: u32) -> Result { diff --git a/library/compiler-builtins/libm-test/src/builtins_wrapper.rs b/library/compiler-builtins/libm-test/src/builtins_wrapper.rs index 0fae45b9e6b91..0398b5d317614 100644 --- a/library/compiler-builtins/libm-test/src/builtins_wrapper.rs +++ b/library/compiler-builtins/libm-test/src/builtins_wrapper.rs @@ -186,3 +186,28 @@ cb_op!(conv, __fixunstfsi, ftoi_f128_u32, (a: f128) -> u32); cb_op!(conv, __fixunstfdi, ftoi_f128_u64, (a: f128) -> u64); #[cfg(f128_enabled)] cb_op!(conv, __fixunstfti, ftoi_f128_u128, (a: f128) -> u128); + +cb_op!(conv, __floatsisf, itof_i32_f32, (a: i32) -> f32); +cb_op!(conv, __floatdisf, itof_i64_f32, (a: i64) -> f32); +cb_op!(conv, __floattisf, itof_i128_f32, (a: i128) -> f32); +cb_op!(conv, __floatsidf, itof_i32_f64, (a: i32) -> f64); +cb_op!(conv, __floatdidf, itof_i64_f64, (a: i64) -> f64); +cb_op!(conv, __floattidf, itof_i128_f64, (a: i128) -> f64); +#[cfg(f128_enabled)] +cb_op!(conv, __floatsitf, itof_i32_f128, (a: i32) -> f128); +#[cfg(f128_enabled)] +cb_op!(conv, __floatditf, itof_i64_f128, (a: i64) -> f128); +#[cfg(f128_enabled)] +cb_op!(conv, __floattitf, itof_i128_f128, (a: i128) -> f128); +cb_op!(conv, __floatunsisf, itof_u32_f32, (a: u32) -> f32); +cb_op!(conv, __floatundisf, itof_u64_f32, (a: u64) -> f32); +cb_op!(conv, __floatuntisf, itof_u128_f32, (a: u128) -> f32); +cb_op!(conv, __floatunsidf, itof_u32_f64, (a: u32) -> f64); +cb_op!(conv, __floatundidf, itof_u64_f64, (a: u64) -> f64); +cb_op!(conv, __floatuntidf, itof_u128_f64, (a: u128) -> f64); +#[cfg(f128_enabled)] +cb_op!(conv, __floatunsitf, itof_u32_f128, (a: u32) -> f128); +#[cfg(f128_enabled)] +cb_op!(conv, __floatunditf, itof_u64_f128, (a: u64) -> f128); +#[cfg(f128_enabled)] +cb_op!(conv, __floatuntitf, itof_u128_f128, (a: u128) -> f128); diff --git a/library/compiler-builtins/libm-test/src/domain.rs b/library/compiler-builtins/libm-test/src/domain.rs index dcbdfc91a88f6..1b2258f4cd2d0 100644 --- a/library/compiler-builtins/libm-test/src/domain.rs +++ b/library/compiler-builtins/libm-test/src/domain.rs @@ -244,6 +244,7 @@ pub fn get_domain( BaseName::Extend => &EitherPrim::UNBOUNDED1[..], BaseName::Narrow => &EitherPrim::UNBOUNDED1[..], BaseName::Ftoi => &EitherPrim::UNBOUNDED1[..], + BaseName::Itof => &EitherPrim::UNBOUNDED1[..], // Math functions BaseName::Acos => &EitherPrim::INVERSE_TRIG_PERIODIC[..], diff --git a/library/compiler-builtins/libm-test/src/generate/case_list.rs b/library/compiler-builtins/libm-test/src/generate/case_list.rs index f04d3cc01dda1..476a84c1663c9 100644 --- a/library/compiler-builtins/libm-test/src/generate/case_list.rs +++ b/library/compiler-builtins/libm-test/src/generate/case_list.rs @@ -390,6 +390,84 @@ fn ftoi_f128_u128_cases() -> Vec> { vec![] } +fn itof_i32_f32_cases() -> Vec> { + vec![] +} + +fn itof_i64_f32_cases() -> Vec> { + vec![] +} + +fn itof_i128_f32_cases() -> Vec> { + vec![] +} + +fn itof_i32_f64_cases() -> Vec> { + vec![] +} + +fn itof_i64_f64_cases() -> Vec> { + vec![] +} + +fn itof_i128_f64_cases() -> Vec> { + vec![] +} + +#[cfg(f128_enabled)] +fn itof_i32_f128_cases() -> Vec> { + vec![] +} + +#[cfg(f128_enabled)] +fn itof_i64_f128_cases() -> Vec> { + vec![] +} + +#[cfg(f128_enabled)] +fn itof_i128_f128_cases() -> Vec> { + vec![] +} + +fn itof_u32_f32_cases() -> Vec> { + vec![] +} + +fn itof_u64_f32_cases() -> Vec> { + vec![] +} + +fn itof_u128_f32_cases() -> Vec> { + vec![] +} + +fn itof_u32_f64_cases() -> Vec> { + vec![] +} + +fn itof_u64_f64_cases() -> Vec> { + vec![] +} + +fn itof_u128_f64_cases() -> Vec> { + vec![] +} + +#[cfg(f128_enabled)] +fn itof_u32_f128_cases() -> Vec> { + vec![] +} + +#[cfg(f128_enabled)] +fn itof_u64_f128_cases() -> Vec> { + vec![] +} + +#[cfg(f128_enabled)] +fn itof_u128_f128_cases() -> Vec> { + vec![] +} + /******************* * libm test cases * *******************/ diff --git a/library/compiler-builtins/libm-test/src/generate/edge_cases.rs b/library/compiler-builtins/libm-test/src/generate/edge_cases.rs index 6d261e06f380e..2cb99aacea895 100644 --- a/library/compiler-builtins/libm-test/src/generate/edge_cases.rs +++ b/library/compiler-builtins/libm-test/src/generate/edge_cases.rs @@ -298,6 +298,28 @@ impl_edge_case_input!(f64); #[cfg(f128_enabled)] impl_edge_case_input!(f128); +macro_rules! impl_edge_case_input_int { + ($ity:ty) => { + impl EdgeCaseInput for ($ity,) + where + Op: MathOp, + { + fn get_cases(ctx: &CheckCtx) -> (impl Iterator, u64) { + let (iter0, steps0) = int_edge_cases(ctx, 0); + let iter0 = iter0.map(|v| (v,)); + (iter0, steps0) + } + } + }; +} + +impl_edge_case_input_int!(i32); +impl_edge_case_input_int!(i64); +impl_edge_case_input_int!(i128); +impl_edge_case_input_int!(u32); +impl_edge_case_input_int!(u64); +impl_edge_case_input_int!(u128); + pub fn get_test_cases( ctx: &CheckCtx, ) -> (impl Iterator + Send + use<'_, Op>, u64) diff --git a/library/compiler-builtins/libm-test/src/generate/random.rs b/library/compiler-builtins/libm-test/src/generate/random.rs index 09a3766c66780..8f76c7d86b07a 100644 --- a/library/compiler-builtins/libm-test/src/generate/random.rs +++ b/library/compiler-builtins/libm-test/src/generate/random.rs @@ -2,7 +2,8 @@ use std::env; use std::ops::RangeInclusive; use std::sync::LazyLock; -use libm::support::Float; +use libm::support::{Float, Int}; +use rand::distr::uniform::SampleUniform; use rand::distr::{Alphanumeric, StandardUniform}; use rand::prelude::Distribution; use rand::{RngExt, SeedableRng}; @@ -10,6 +11,7 @@ use rand_chacha::ChaCha8Rng; use super::KnownSize; use crate::CheckCtx; +use crate::num::full_range; use crate::run_cfg::{int_range, iteration_count}; pub(crate) const SEED_ENV: &str = "LIBM_SEED"; @@ -43,9 +45,12 @@ where } /// Generate a sequence of deterministically random `i32`s within a specified range. -fn random_ints(count: u64, range: RangeInclusive) -> impl Iterator { +fn random_ints(count: u64, range: RangeInclusive) -> impl Iterator +where + I: Int + SampleUniform, +{ let mut rng = ChaCha8Rng::from_seed(*SEED); - (0..count).map(move |_| rng.random_range::(range.clone())) + (0..count).map(move |_| rng.random_range::(range.clone())) } macro_rules! impl_random_input { @@ -86,7 +91,7 @@ macro_rules! impl_random_input { fn get_cases(ctx: &CheckCtx) -> (impl Iterator, u64) { let count0 = iteration_count(ctx, 0); let count1 = iteration_count(ctx, 1); - let range0 = int_range(ctx, 0); + let range0 = int_range::(ctx, 0).unwrap_or(full_range()); let iter = random_ints(count0, range0) .flat_map(move |f1: i32| random_floats(count1).map(move |f2: $fty| (f1, f2))); (iter, count0 * count1) @@ -97,7 +102,7 @@ macro_rules! impl_random_input { fn get_cases(ctx: &CheckCtx) -> (impl Iterator, u64) { let count0 = iteration_count(ctx, 0); let count1 = iteration_count(ctx, 1); - let range1 = int_range(ctx, 1); + let range1 = int_range::(ctx, 1).unwrap_or(full_range()); let iter = random_floats(count0).flat_map(move |f1: $fty| { random_ints(count1, range1.clone()).map(move |f2: i32| (f1, f2)) }); @@ -114,6 +119,26 @@ impl_random_input!(f64); #[cfg(f128_enabled)] impl_random_input!(f128); +macro_rules! impl_random_input_int { + ($ity:ty) => { + impl RandomInput for ($ity,) { + fn get_cases(ctx: &CheckCtx) -> (impl Iterator, u64) { + let count = iteration_count(ctx, 0); + let range = int_range::<$ity>(ctx, 0).unwrap_or(full_range()); + let iter = random_ints(count, range).map(|f: $ity| (f,)); + (iter, count) + } + } + }; +} + +impl_random_input_int!(i32); +impl_random_input_int!(i64); +impl_random_input_int!(i128); +impl_random_input_int!(u32); +impl_random_input_int!(u64); +impl_random_input_int!(u128); + /// Create a test case iterator. pub fn get_test_cases( ctx: &CheckCtx, diff --git a/library/compiler-builtins/libm-test/src/generate/spaced.rs b/library/compiler-builtins/libm-test/src/generate/spaced.rs index 0a31f232ee301..f7b97b3463ddb 100644 --- a/library/compiler-builtins/libm-test/src/generate/spaced.rs +++ b/library/compiler-builtins/libm-test/src/generate/spaced.rs @@ -1,9 +1,10 @@ use std::fmt; use std::ops::RangeInclusive; -use libm::support::{Float, MinInt}; +use libm::support::{Float, Int, MinInt}; use crate::domain::get_domain; +use crate::num::full_range; use crate::run_cfg::{int_range, iteration_count}; use crate::{Arg0, Arg1, Arg2, CheckCtx, MathOp, linear_ints, logspace}; @@ -69,7 +70,14 @@ fn value_count() -> Option where u64: TryFrom, { - u64::try_from(F::Int::MAX) + value_count_int::() +} + +fn value_count_int() -> Option +where + u64: TryFrom, +{ + u64::try_from(I::MAX.abs_diff(I::MIN)) .ok() .and_then(|max| max.checked_add(1)) } @@ -180,7 +188,7 @@ macro_rules! impl_spaced_input { Op: MathOp, { fn get_cases(ctx: &CheckCtx) -> (impl Iterator, u64) { - let range0 = int_range(ctx, 0); + let range0 = int_range(ctx, 0).unwrap_or(full_range()); let max_steps0 = iteration_count(ctx, 0); let max_steps1 = iteration_count(ctx, 1); match value_count::>() { @@ -211,7 +219,7 @@ macro_rules! impl_spaced_input { { fn get_cases(ctx: &CheckCtx) -> (impl Iterator, u64) { let max_steps0 = iteration_count(ctx, 0); - let range1 = int_range(ctx, 1); + let range1 = int_range(ctx, 1).unwrap_or(full_range()); let max_steps1 = iteration_count(ctx, 1); match value_count::>() { Some(count0) if count0 <= max_steps0 => { @@ -245,6 +253,38 @@ impl_spaced_input!(f64); #[cfg(f128_enabled)] impl_spaced_input!(f128); +macro_rules! impl_spaced_input_int { + ($ity:ty) => { + impl SpacedInput for ($ity,) + where + Op: MathOp, + { + fn get_cases(ctx: &CheckCtx) -> (impl Iterator, u64) { + let range = int_range(ctx, 0).unwrap_or(full_range()); + let max_steps0 = iteration_count(ctx, 0); + match value_count_int::>() { + Some(steps0) if steps0 <= max_steps0 => { + let iter0 = range.map(|v| (v,)); + (EitherIter::A(iter0), steps0) + } + _ => { + let (iter0, steps0) = linear_ints::>(range, max_steps0); + let iter0 = iter0.map(|v| (v,)); + (EitherIter::B(iter0), steps0) + } + } + } + } + }; +} + +impl_spaced_input_int!(i32); +impl_spaced_input_int!(i64); +impl_spaced_input_int!(i128); +impl_spaced_input_int!(u32); +impl_spaced_input_int!(u64); +impl_spaced_input_int!(u128); + /// Create a test case iterator for extensive inputs. Also returns the total test case count. pub fn get_test_cases( ctx: &CheckCtx, diff --git a/library/compiler-builtins/libm-test/src/mpfloat.rs b/library/compiler-builtins/libm-test/src/mpfloat.rs index 69a9727dd5ed3..9667120ed128e 100644 --- a/library/compiler-builtins/libm-test/src/mpfloat.rs +++ b/library/compiler-builtins/libm-test/src/mpfloat.rs @@ -213,6 +213,24 @@ libm_macros::for_each_function! { ilogbf, ilogbf128, ilogbf16, + itof_i128_f128, + itof_i128_f32, + itof_i128_f64, + itof_i32_f128, + itof_i32_f32, + itof_i32_f64, + itof_i64_f128, + itof_i64_f32, + itof_i64_f64, + itof_u128_f128, + itof_u128_f32, + itof_u128_f64, + itof_u32_f128, + itof_u32_f32, + itof_u32_f64, + itof_u64_f128, + itof_u64_f32, + itof_u64_f64, jn, jnf, ldexp, @@ -828,7 +846,7 @@ macro_rules! impl_extend_trunc { }; } -macro_rules! impl_ftoi { +macro_rules! impl_ftoi_itof { ($fty:ty, $ity:ty) => { paste::paste! { impl MpOp for crate::op::[]::Routine { @@ -853,6 +871,19 @@ macro_rules! impl_ftoi { }) } } + + impl MpOp for crate::op::[]::Routine { + type MpTy = MpFloat; + + fn new_mp() -> Self::MpTy { + new_mpfloat::() + } + + fn run(this: &mut Self::MpTy, input: Self::RustArgs) -> Self::RustRet { + this.assign(input.0); + prep_retval::(this, Ordering::Equal) + } + } } }; } @@ -885,30 +916,30 @@ impl_extend_trunc!(f32, f128); #[cfg(f128_enabled)] impl_extend_trunc!(f64, f128); -impl_ftoi!(f32, i32); -impl_ftoi!(f32, i64); -impl_ftoi!(f32, i128); -impl_ftoi!(f32, u32); -impl_ftoi!(f32, u64); -impl_ftoi!(f32, u128); -impl_ftoi!(f64, i32); -impl_ftoi!(f64, i64); -impl_ftoi!(f64, i128); -impl_ftoi!(f64, u32); -impl_ftoi!(f64, u64); -impl_ftoi!(f64, u128); +impl_ftoi_itof!(f32, i32); +impl_ftoi_itof!(f32, i64); +impl_ftoi_itof!(f32, i128); +impl_ftoi_itof!(f32, u32); +impl_ftoi_itof!(f32, u64); +impl_ftoi_itof!(f32, u128); +impl_ftoi_itof!(f64, i32); +impl_ftoi_itof!(f64, i64); +impl_ftoi_itof!(f64, i128); +impl_ftoi_itof!(f64, u32); +impl_ftoi_itof!(f64, u64); +impl_ftoi_itof!(f64, u128); #[cfg(f128_enabled)] -impl_ftoi!(f128, i32); +impl_ftoi_itof!(f128, i32); #[cfg(f128_enabled)] -impl_ftoi!(f128, i64); +impl_ftoi_itof!(f128, i64); #[cfg(f128_enabled)] -impl_ftoi!(f128, i128); +impl_ftoi_itof!(f128, i128); #[cfg(f128_enabled)] -impl_ftoi!(f128, u32); +impl_ftoi_itof!(f128, u32); #[cfg(f128_enabled)] -impl_ftoi!(f128, u64); +impl_ftoi_itof!(f128, u64); #[cfg(f128_enabled)] -impl_ftoi!(f128, u128); +impl_ftoi_itof!(f128, u128); // `lgamma_r` is not a simple suffix so we can't use the above macro. impl MpOp for crate::op::lgamma_r::Routine { diff --git a/library/compiler-builtins/libm-test/src/num.rs b/library/compiler-builtins/libm-test/src/num.rs index 3237c85039d57..efa87d6351597 100644 --- a/library/compiler-builtins/libm-test/src/num.rs +++ b/library/compiler-builtins/libm-test/src/num.rs @@ -1,6 +1,7 @@ //! Helpful numeric operations. use std::cmp::min; +use std::fmt; use std::ops::RangeInclusive; use libm::support::Float; @@ -257,15 +258,20 @@ where } /// Returns an iterator of up to `steps` integers evenly distributed. -pub fn linear_ints( - range: RangeInclusive, +pub fn linear_ints( + range: RangeInclusive, steps: u64, -) -> (impl Iterator + Clone, u64) { - let steps = steps.checked_sub(1).unwrap(); - let between = u64::from(range.start().abs_diff(*range.end())); - let spacing = i32::try_from((between / steps).max(1)).unwrap(); - let steps = steps.min(between); - let mut x: i32 = *range.start(); +) -> (impl Iterator + Clone, u64) +where + I: Int + TryFrom, + u128: TryFrom, +{ + let spaces: u128 = steps.checked_sub(1).unwrap().into(); + let between = u128::try_from(range.start().abs_diff(*range.end())).expect("out of u128 range"); + let spacing = I::try_from((between / spaces).max(1)).unwrap(); + let steps = spaces.min(between); + let steps = u64::try_from(steps).expect("> u64::MAX steps"); + let mut x: I = *range.start(); ( (0..=steps).map(move |_| { let res = x; @@ -278,6 +284,11 @@ pub fn linear_ints( ) } +/// `..` as a `RangeInclusive`. +pub fn full_range() -> RangeInclusive { + I::MIN..=I::MAX +} + #[cfg(test)] mod tests { use std::cmp::max; diff --git a/library/compiler-builtins/libm-test/src/precision.rs b/library/compiler-builtins/libm-test/src/precision.rs index da87df49bf52c..39225c6adbb14 100644 --- a/library/compiler-builtins/libm-test/src/precision.rs +++ b/library/compiler-builtins/libm-test/src/precision.rs @@ -27,7 +27,7 @@ pub fn default_ulp(ctx: &CheckCtx) -> Option { Bn::Eq | Bn::Ne | Bn::Gt | Bn::Ge | Bn::Lt | Bn::Le | Bn::Unord | Bn::Ilogb => return None, // Convrsion operations must be precise. - BaseName::Extend | BaseName::Narrow | BaseName::Ftoi => 0, + Bn::Extend | Bn::Narrow | Bn::Ftoi | Bn::Itof => 0, // Operations that require exact results. This list should correlate with what we // have documented at . @@ -537,3 +537,10 @@ impl MaybeOverride<(f32, f32, f32)> for SpecialCase {} impl MaybeOverride<(f64, f64, f64)> for SpecialCase {} #[cfg(f128_enabled)] impl MaybeOverride<(f128, f128, f128)> for SpecialCase {} + +impl MaybeOverride<(i32,)> for SpecialCase {} +impl MaybeOverride<(i64,)> for SpecialCase {} +impl MaybeOverride<(i128,)> for SpecialCase {} +impl MaybeOverride<(u32,)> for SpecialCase {} +impl MaybeOverride<(u64,)> for SpecialCase {} +impl MaybeOverride<(u128,)> for SpecialCase {} diff --git a/library/compiler-builtins/libm-test/src/run_cfg.rs b/library/compiler-builtins/libm-test/src/run_cfg.rs index b4be30cfc5a60..63cb6910d0597 100644 --- a/library/compiler-builtins/libm-test/src/run_cfg.rs +++ b/library/compiler-builtins/libm-test/src/run_cfg.rs @@ -2,7 +2,7 @@ use std::ops::RangeInclusive; use std::sync::LazyLock; -use std::{env, str}; +use std::{env, fmt, str}; use crate::generate::random::{SEED, SEED_ENV}; use crate::{BaseName, Group, Identifier, test_log}; @@ -347,12 +347,23 @@ pub fn iteration_count(ctx: &CheckCtx, argnum: usize) -> u64 { ntests } -/// Some tests require that an integer be kept within reasonable limits; generate that here. -pub fn int_range(ctx: &CheckCtx, argnum: usize) -> RangeInclusive { +/// Some tests require that an integer be kept within reasonable limits; if that is needed, retun +/// a limited range. +pub fn int_range(ctx: &CheckCtx, argnum: usize) -> Option> +where + I: TryFrom, +{ let t_env = TestEnv::from_env(ctx); + let argcount = ctx.fn_ident.math_op().rust_sig.args.len(); + assert!( + argnum < argcount, + "requested argnum {argnum} of only {argcount} args" + ); + + // Use the whole range for most functions. if !matches!(ctx.base_name, BaseName::Jn | BaseName::Yn) { - return i32::MIN..=i32::MAX; + return None; } assert_eq!( @@ -370,12 +381,14 @@ pub fn int_range(ctx: &CheckCtx, argnum: usize) -> RangeInclusive { let extensive_range = (-0xfff)..=0xfffff; - match ctx.gen_kind { + let ret = match ctx.gen_kind { _ if ctx.extensive => extensive_range, GeneratorKind::Spaced | GeneratorKind::Random => non_extensive_range, GeneratorKind::EdgeCases => extensive_range, GeneratorKind::List => unimplemented!("shoudn't need range for {:?}", ctx.gen_kind), - } + }; + + Some(I::try_from(*ret.start()).unwrap()..=I::try_from(*ret.end()).unwrap()) } /// For domain tests, limit how many asymptotes or specified check points we test. From 6ff91b047041f4cb48efce52738cdc660877f7c7 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Wed, 25 Mar 2026 04:08:19 -0500 Subject: [PATCH 032/183] test: Cover compiler-builtins integer bit ops in libm-test Add the following to the test infrastructure: * `__ashlsi3` * `__ashldi3` * `__ashlti3` * `__ashrsi3` * `__ashrdi3` * `__ashrti3` * `__lshrsi3` * `__lshrdi3` * `__lshrti3` * `__clzsi2` * `__clzdi2` * `__clzti2` * `__ctzsi2` * `__ctzdi2` * `__ctzti2` --- .../crates/libm-macros/src/lib.rs | 1 + .../crates/libm-macros/src/shared.rs | 115 ++++++++++++++++++ .../compiler-builtins/crates/util/src/main.rs | 7 ++ .../libm-test/src/builtins_wrapper.rs | 24 ++++ .../compiler-builtins/libm-test/src/domain.rs | 9 ++ .../libm-test/src/generate/case_list.rs | 64 ++++++++++ .../libm-test/src/generate/edge_cases.rs | 30 +++++ .../libm-test/src/generate/random.rs | 13 ++ .../libm-test/src/generate/spaced.rs | 29 +++++ .../libm-test/src/mpfloat.rs | 110 ++++++++++++++++- .../libm-test/src/precision.rs | 20 ++- .../libm-test/src/run_cfg.rs | 27 +++- .../libm-test/src/test_traits.rs | 2 +- 13 files changed, 445 insertions(+), 6 deletions(-) diff --git a/library/compiler-builtins/crates/libm-macros/src/lib.rs b/library/compiler-builtins/crates/libm-macros/src/lib.rs index acb7edf704374..09369e8de3a93 100644 --- a/library/compiler-builtins/crates/libm-macros/src/lib.rs +++ b/library/compiler-builtins/crates/libm-macros/src/lib.rs @@ -535,6 +535,7 @@ impl ToTokens for Ty { Ty::U32 => quote! { u32 }, Ty::U64 => quote! { u64 }, Ty::U128 => quote! { u128 }, + Ty::USize => quote! { usize }, Ty::Bool => quote! { bool }, Ty::CInt => quote! { ::core::ffi::c_int }, Ty::MutF16 => quote! { &'a mut f16 }, diff --git a/library/compiler-builtins/crates/libm-macros/src/shared.rs b/library/compiler-builtins/crates/libm-macros/src/shared.rs index c875068bb2607..716736fa1aeec 100644 --- a/library/compiler-builtins/crates/libm-macros/src/shared.rs +++ b/library/compiler-builtins/crates/libm-macros/src/shared.rs @@ -595,6 +595,116 @@ const ALL_OPERATIONS_NESTED: &[NestedOp] = &[ fn_list: &["itof_u128_f128"], scope: OpScope::BuiltinsPublic, }, + /* int shifts */ + NestedOp { + rust_sig: Signature { + args: &[Ty::U32, Ty::U32], + returns: &[Ty::U32], + }, + c_sig: None, + fn_list: &["ashl_u32", "lshr_u32"], + scope: OpScope::BuiltinsPublic, + }, + NestedOp { + rust_sig: Signature { + args: &[Ty::U64, Ty::U32], + returns: &[Ty::U64], + }, + c_sig: None, + fn_list: &["ashl_u64", "lshr_u64"], + scope: OpScope::BuiltinsPublic, + }, + NestedOp { + rust_sig: Signature { + args: &[Ty::U128, Ty::U32], + returns: &[Ty::U128], + }, + c_sig: None, + fn_list: &["ashl_u128", "lshr_u128"], + scope: OpScope::BuiltinsPublic, + }, + NestedOp { + rust_sig: Signature { + args: &[Ty::I32, Ty::U32], + returns: &[Ty::I32], + }, + c_sig: None, + fn_list: &["ashr_i32"], + scope: OpScope::BuiltinsPublic, + }, + NestedOp { + rust_sig: Signature { + args: &[Ty::I64, Ty::U32], + returns: &[Ty::I64], + }, + c_sig: None, + fn_list: &["ashr_i64"], + scope: OpScope::BuiltinsPublic, + }, + NestedOp { + rust_sig: Signature { + args: &[Ty::I128, Ty::U32], + returns: &[Ty::I128], + }, + c_sig: None, + fn_list: &["ashr_i128"], + scope: OpScope::BuiltinsPublic, + }, + /* int bitwise ops */ + NestedOp { + rust_sig: Signature { + args: &[Ty::U32], + returns: &[Ty::USize], + }, + c_sig: None, + fn_list: &["leading_zeros_u32"], + scope: OpScope::BuiltinsPublic, + }, + NestedOp { + rust_sig: Signature { + args: &[Ty::U64], + returns: &[Ty::USize], + }, + c_sig: None, + fn_list: &["leading_zeros_u64"], + scope: OpScope::BuiltinsPublic, + }, + NestedOp { + rust_sig: Signature { + args: &[Ty::U128], + returns: &[Ty::USize], + }, + c_sig: None, + fn_list: &["leading_zeros_u128"], + scope: OpScope::BuiltinsPublic, + }, + NestedOp { + rust_sig: Signature { + args: &[Ty::U32], + returns: &[Ty::USize], + }, + c_sig: None, + fn_list: &["trailing_zeros_u32"], + scope: OpScope::BuiltinsPublic, + }, + NestedOp { + rust_sig: Signature { + args: &[Ty::U64], + returns: &[Ty::USize], + }, + c_sig: None, + fn_list: &["trailing_zeros_u64"], + scope: OpScope::BuiltinsPublic, + }, + NestedOp { + rust_sig: Signature { + args: &[Ty::U128], + returns: &[Ty::USize], + }, + c_sig: None, + fn_list: &["trailing_zeros_u128"], + scope: OpScope::BuiltinsPublic, + }, /******************* * libm operations * *******************/ @@ -1098,6 +1208,7 @@ pub enum Ty { U32, U64, U128, + USize, Bool, CInt, MutF16, @@ -1119,6 +1230,7 @@ impl Ty { Ty::F32 | Ty::I32 | Ty::U32 | Ty::MutF32 | Ty::MutI32 => 32, Ty::F64 | Ty::I64 | Ty::U64 | Ty::MutF64 => 64, Ty::F128 | Ty::I128 | Ty::U128 | Ty::MutF128 => 128, + Ty::USize => usize::BITS, // Assume we're not testing on a 16-bit system Ty::CInt | Ty::MutCInt => 32, } @@ -1137,6 +1249,7 @@ impl Ty { | Ty::U32 | Ty::U64 | Ty::U128 + | Ty::USize | Ty::Bool | Ty::CInt | Ty::MutI32 @@ -1160,6 +1273,7 @@ impl Ty { | Ty::U32 | Ty::U64 | Ty::U128 + | Ty::USize | Ty::Bool | Ty::CInt | Ty::MutI32 @@ -1192,6 +1306,7 @@ impl fmt::Display for Ty { Ty::U32 => "u32", Ty::U64 => "u64", Ty::U128 => "u128", + Ty::USize => "usize", Ty::Bool => "bool", Ty::CInt => "::core::ffi::c_int", Ty::MutF16 => "&mut f16", diff --git a/library/compiler-builtins/crates/util/src/main.rs b/library/compiler-builtins/crates/util/src/main.rs index 2810149b2412d..04fb090a81ff5 100644 --- a/library/compiler-builtins/crates/util/src/main.rs +++ b/library/compiler-builtins/crates/util/src/main.rs @@ -318,6 +318,13 @@ macro_rules! impl_parse_tuple_int { } } + impl ParseTuple for ($ty, u32) { + fn parse(input: &[&str]) -> Self { + assert_eq!(input.len(), 2, "expected two arguments, got {input:?}"); + (parse(input, 0), parse(input, 1)) + } + } + impl FromStrRadix for $ty { fn from_str_radix(s: &str, radix: u32) -> Result { let s = strip_radix_prefix(s, radix); diff --git a/library/compiler-builtins/libm-test/src/builtins_wrapper.rs b/library/compiler-builtins/libm-test/src/builtins_wrapper.rs index 0398b5d317614..9fac5e78f9642 100644 --- a/library/compiler-builtins/libm-test/src/builtins_wrapper.rs +++ b/library/compiler-builtins/libm-test/src/builtins_wrapper.rs @@ -11,6 +11,11 @@ macro_rules! cb_op { compiler_builtins::float::$mod::$cb_name($($arg),*) } }; + (@int $mod:ident, $cb_name:ident, $new_name:ident, ($($arg:ident: $ArgTy:ty),*) -> $RetTy:ty) => { + pub fn $new_name($($arg: $ArgTy),*) -> $RetTy { + compiler_builtins::int::$mod::$cb_name($($arg),*) + } + }; // Common signatures (@binop $ty:ty, $mod:ident, $cb_name:ident, $new_name:ident) => { @@ -211,3 +216,22 @@ cb_op!(conv, __floatunsitf, itof_u32_f128, (a: u32) -> f128); cb_op!(conv, __floatunditf, itof_u64_f128, (a: u64) -> f128); #[cfg(f128_enabled)] cb_op!(conv, __floatuntitf, itof_u128_f128, (a: u128) -> f128); + +/* int ops */ + +cb_op!(@int shift, __ashlsi3, ashl_u32, (a: u32, b: u32) -> u32); +cb_op!(@int shift, __ashldi3, ashl_u64, (a: u64, b: u32) -> u64); +cb_op!(@int shift, __ashlti3, ashl_u128, (a: u128, b: u32) -> u128); +cb_op!(@int shift, __ashrsi3, ashr_i32, (a: i32, b: u32) -> i32); +cb_op!(@int shift, __ashrdi3, ashr_i64, (a: i64, b: u32) -> i64); +cb_op!(@int shift, __ashrti3, ashr_i128, (a: i128, b: u32) -> i128); +cb_op!(@int shift, __lshrsi3, lshr_u32, (a: u32, b: u32) -> u32); +cb_op!(@int shift, __lshrdi3, lshr_u64, (a: u64, b: u32) -> u64); +cb_op!(@int shift, __lshrti3, lshr_u128, (a: u128, b: u32) -> u128); + +cb_op!(@int leading_zeros, __clzsi2, leading_zeros_u32, (a: u32) -> usize); +cb_op!(@int leading_zeros, __clzdi2, leading_zeros_u64, (a: u64) -> usize); +cb_op!(@int leading_zeros, __clzti2, leading_zeros_u128, (a: u128) -> usize); +cb_op!(@int trailing_zeros, __ctzsi2, trailing_zeros_u32, (a: u32) -> usize); +cb_op!(@int trailing_zeros, __ctzdi2, trailing_zeros_u64, (a: u64) -> usize); +cb_op!(@int trailing_zeros, __ctzti2, trailing_zeros_u128, (a: u128) -> usize); diff --git a/library/compiler-builtins/libm-test/src/domain.rs b/library/compiler-builtins/libm-test/src/domain.rs index 1b2258f4cd2d0..c2e4317086f18 100644 --- a/library/compiler-builtins/libm-test/src/domain.rs +++ b/library/compiler-builtins/libm-test/src/domain.rs @@ -246,6 +246,15 @@ pub fn get_domain( BaseName::Ftoi => &EitherPrim::UNBOUNDED1[..], BaseName::Itof => &EitherPrim::UNBOUNDED1[..], + // Integer ops + // Shifts technically aren't unbounded, but its range is restricted elsewhere in + // our test generators. + BaseName::Ashl => &EitherPrim::UNBOUNDED2[..], + BaseName::Ashr => &EitherPrim::UNBOUNDED2[..], + BaseName::Lshr => &EitherPrim::UNBOUNDED2[..], + BaseName::LeadingZeros => &EitherPrim::UNBOUNDED1[..], + BaseName::TrailingZeros => &EitherPrim::UNBOUNDED1[..], + // Math functions BaseName::Acos => &EitherPrim::INVERSE_TRIG_PERIODIC[..], BaseName::Acosh => &EitherPrim::ACOSH[..], diff --git a/library/compiler-builtins/libm-test/src/generate/case_list.rs b/library/compiler-builtins/libm-test/src/generate/case_list.rs index 476a84c1663c9..f6c58dd1ce546 100644 --- a/library/compiler-builtins/libm-test/src/generate/case_list.rs +++ b/library/compiler-builtins/libm-test/src/generate/case_list.rs @@ -468,6 +468,70 @@ fn itof_u128_f128_cases() -> Vec> { vec![] } +/* int shifts */ + +fn ashl_u32_cases() -> Vec> { + vec![] +} + +fn ashl_u64_cases() -> Vec> { + vec![] +} + +fn ashl_u128_cases() -> Vec> { + vec![] +} + +fn ashr_i32_cases() -> Vec> { + vec![] +} + +fn ashr_i64_cases() -> Vec> { + vec![] +} + +fn ashr_i128_cases() -> Vec> { + vec![] +} + +fn lshr_u32_cases() -> Vec> { + vec![] +} + +fn lshr_u64_cases() -> Vec> { + vec![] +} + +fn lshr_u128_cases() -> Vec> { + vec![] +} + +/* int bitwise ops */ + +fn leading_zeros_u32_cases() -> Vec> { + vec![] +} + +fn leading_zeros_u64_cases() -> Vec> { + vec![] +} + +fn leading_zeros_u128_cases() -> Vec> { + vec![] +} + +fn trailing_zeros_u32_cases() -> Vec> { + vec![] +} + +fn trailing_zeros_u64_cases() -> Vec> { + vec![] +} + +fn trailing_zeros_u128_cases() -> Vec> { + vec![] +} + /******************* * libm test cases * *******************/ diff --git a/library/compiler-builtins/libm-test/src/generate/edge_cases.rs b/library/compiler-builtins/libm-test/src/generate/edge_cases.rs index 2cb99aacea895..761b5d92c97cf 100644 --- a/library/compiler-builtins/libm-test/src/generate/edge_cases.rs +++ b/library/compiler-builtins/libm-test/src/generate/edge_cases.rs @@ -169,6 +169,22 @@ where int_count_around((emin_sn - emax).cast(), near_points, &mut values); } + if matches!( + ctx.base_name, + BaseName::Ashl | BaseName::Ashr | BaseName::Lshr + ) { + // Don't test shift values that are allowed to invoke UB. + let max = match ctx.fn_ident.math_op().rust_sig.args[0] { + Ty::U32 | Ty::I32 => 31, + Ty::U64 | Ty::I64 => 63, + Ty::U128 | Ty::I128 => 127, + ty => panic!("unexpected type {ty}"), + }; + let max: I = max.cast(); + int_count_around(max, near_points, &mut values); + values.retain(|v| *v <= max); + } + values.sort(); values.dedup(); let count = values.len().try_into().unwrap(); @@ -310,6 +326,20 @@ macro_rules! impl_edge_case_input_int { (iter0, steps0) } } + + impl EdgeCaseInput for ($ity, u32) + where + Op: MathOp, + { + fn get_cases(ctx: &CheckCtx) -> (impl Iterator, u64) { + let (iter0, steps0) = int_edge_cases(ctx, 0); + let (iter1, steps1) = int_edge_cases(ctx, 1); + let iter = + iter0.flat_map(move |first| iter1.clone().map(move |second| (first, second))); + let count = steps0.checked_mul(steps1).unwrap(); + (iter, count) + } + } }; } diff --git a/library/compiler-builtins/libm-test/src/generate/random.rs b/library/compiler-builtins/libm-test/src/generate/random.rs index 8f76c7d86b07a..c621d631490c6 100644 --- a/library/compiler-builtins/libm-test/src/generate/random.rs +++ b/library/compiler-builtins/libm-test/src/generate/random.rs @@ -129,6 +129,19 @@ macro_rules! impl_random_input_int { (iter, count) } } + + impl RandomInput for ($ity, u32) { + fn get_cases(ctx: &CheckCtx) -> (impl Iterator, u64) { + let count0 = iteration_count(ctx, 0); + let count1 = iteration_count(ctx, 1); + let range0 = int_range::<$ity>(ctx, 1).unwrap_or(full_range()); + let range1 = int_range::(ctx, 1).unwrap_or(full_range()); + let iter = random_ints(count0, range0).flat_map(move |f1: $ity| { + random_ints(count1, range1.clone()).map(move |f2: u32| (f1, f2)) + }); + (iter, count0 * count1) + } + } }; } diff --git a/library/compiler-builtins/libm-test/src/generate/spaced.rs b/library/compiler-builtins/libm-test/src/generate/spaced.rs index f7b97b3463ddb..dd5c728ca2849 100644 --- a/library/compiler-builtins/libm-test/src/generate/spaced.rs +++ b/library/compiler-builtins/libm-test/src/generate/spaced.rs @@ -275,6 +275,35 @@ macro_rules! impl_spaced_input_int { } } } + + impl SpacedInput for ($ity, u32) + where + Op: MathOp, + { + fn get_cases(ctx: &CheckCtx) -> (impl Iterator, u64) { + let range0 = int_range(ctx, 0).unwrap_or(full_range()); + let range1 = int_range(ctx, 1).unwrap_or(full_range()); + let max_steps0 = iteration_count(ctx, 0); + let max_steps1 = iteration_count(ctx, 0); + match value_count_int::>() { + Some(count) if count <= max_steps0 && count < max_steps1 => { + let iter = range0.flat_map(move |first| { + range1.clone().map(move |second| (first, second)) + }); + (EitherIter::A(iter), count.checked_mul(count).unwrap()) + } + _ => { + let (iter0, steps0) = linear_ints::>(range0, max_steps0); + let (iter1, steps1) = linear_ints::>(range1, max_steps1); + let iter = iter0.flat_map(move |first| { + iter1.clone().map(move |second| (first, second)) + }); + let count = steps0.checked_mul(steps1).unwrap(); + (EitherIter::B(iter), count) + } + } + } + } }; } diff --git a/library/compiler-builtins/libm-test/src/mpfloat.rs b/library/compiler-builtins/libm-test/src/mpfloat.rs index 9667120ed128e..dd439e1d7b012 100644 --- a/library/compiler-builtins/libm-test/src/mpfloat.rs +++ b/library/compiler-builtins/libm-test/src/mpfloat.rs @@ -6,12 +6,12 @@ use std::cmp::Ordering; use rug::Assign; -pub use rug::Float as MpFloat; -use rug::az::{self, Az, CheckedCast}; +use rug::az::{self, Az, CheckedCast, WrappingAs}; use rug::float::Round::Nearest; use rug::ops::{ AddAssignRound, DivAssignRound, MulAssignRound, PowAssignRound, RemAssignRound, SubAssignRound, }; +pub use rug::{Float as MpFloat, Integer as MpInt}; use crate::{Arg0, Arg1, Arg2, Float, MathOp, Ret0, Ret1}; @@ -139,6 +139,12 @@ libm_macros::for_each_function! { addf16, addf32, addf64, + ashl_u128, + ashl_u32, + ashl_u64, + ashr_i128, + ashr_i32, + ashr_i64, ceil, ceilf, ceilf128, @@ -237,6 +243,9 @@ libm_macros::for_each_function! { ldexpf, ldexpf128, ldexpf16, + leading_zeros_u128, + leading_zeros_u32, + leading_zeros_u64, lef128, lef16, lef32, @@ -245,6 +254,9 @@ libm_macros::for_each_function! { lgamma_r, lgammaf, lgammaf_r, + lshr_u128, + lshr_u32, + lshr_u64, ltf128, ltf16, ltf32, @@ -294,6 +306,9 @@ libm_macros::for_each_function! { subf16, subf32, subf64, + trailing_zeros_u128, + trailing_zeros_u32, + trailing_zeros_u64, trunc, truncf, truncf128, @@ -1021,3 +1036,94 @@ impl MpOp for crate::op::nextafterf::Routine { unimplemented!("nextafter does not yet have a MPFR operation"); } } + +macro_rules! impl_int_ops { + ($ity:ty) => { + paste::paste! { + impl MpOp for crate::op::[]::Routine { + type MpTy = MpInt; + + fn new_mp() -> Self::MpTy { + MpInt::new() + } + + fn run(this: &mut Self::MpTy, input: Self::RustArgs) -> Self::RustRet { + assert!(input.1 < Arg0::::BITS, "got UB shift {}", input.1); + this.assign(input.0); + *this <<= input.1; + (&*this).wrapping_as::>() + } + } + + impl MpOp for crate::op::[]::Routine { + type MpTy = MpInt; + + fn new_mp() -> Self::MpTy { + MpInt::new() + } + + fn run(this: &mut Self::MpTy, input: Self::RustArgs) -> Self::RustRet { + assert!(input.1 < Arg0::::BITS, "got UB shift {}", input.1); + this.assign(input.0); + *this >>= input.1; + (&*this).wrapping_as::>() + } + } + + impl MpOp for crate::op::[]::Routine { + type MpTy = MpInt; + + fn new_mp() -> Self::MpTy { + MpInt::new() + } + + fn run(this: &mut Self::MpTy, input: Self::RustArgs) -> Self::RustRet { + this.assign(input.0); + (Arg0::::BITS - this.significant_bits()).try_into().unwrap() + } + } + + impl MpOp for crate::op::[]::Routine { + type MpTy = MpInt; + + fn new_mp() -> Self::MpTy { + MpInt::new() + } + + fn run(this: &mut Self::MpTy, input: Self::RustArgs) -> Self::RustRet { + this.assign(input.0); + this.find_one(0).unwrap_or(Arg0::::BITS).try_into().unwrap() + } + } + } + }; +} + +impl_int_ops!(u32); +impl_int_ops!(u64); +impl_int_ops!(u128); + +macro_rules! impl_signed_int_ops { + ($ity:ty) => { + paste::paste! { + impl MpOp for crate::op::[]::Routine { + type MpTy = MpInt; + + fn new_mp() -> Self::MpTy { + MpInt::new() + } + + fn run(this: &mut Self::MpTy, input: Self::RustArgs) -> Self::RustRet { + assert!(input.1 < Arg0::::BITS, "got UB shift {}", input.1); + this.assign(input.0); + *this >>= input.1; + (&*this).wrapping_as::>() + } + } + } + }; +} + +impl_signed_int_ops!(i32); +impl_signed_int_ops!(i64); +impl_signed_int_ops!(i128); diff --git a/library/compiler-builtins/libm-test/src/precision.rs b/library/compiler-builtins/libm-test/src/precision.rs index 39225c6adbb14..56d4359e39c78 100644 --- a/library/compiler-builtins/libm-test/src/precision.rs +++ b/library/compiler-builtins/libm-test/src/precision.rs @@ -24,7 +24,19 @@ pub fn default_ulp(ctx: &CheckCtx) -> Option { Bn::Powi => 1000, // Operations that only return non-float results - Bn::Eq | Bn::Ne | Bn::Gt | Bn::Ge | Bn::Lt | Bn::Le | Bn::Unord | Bn::Ilogb => return None, + Bn::Eq + | Bn::Ne + | Bn::Gt + | Bn::Ge + | Bn::Lt + | Bn::Le + | Bn::Unord + | Bn::Ilogb + | Bn::Ashl + | Bn::Ashr + | Bn::Lshr + | Bn::LeadingZeros + | Bn::TrailingZeros => return None, // Convrsion operations must be precise. Bn::Extend | Bn::Narrow | Bn::Ftoi | Bn::Itof => 0, @@ -544,3 +556,9 @@ impl MaybeOverride<(i128,)> for SpecialCase {} impl MaybeOverride<(u32,)> for SpecialCase {} impl MaybeOverride<(u64,)> for SpecialCase {} impl MaybeOverride<(u128,)> for SpecialCase {} +impl MaybeOverride<(i32, u32)> for SpecialCase {} +impl MaybeOverride<(i64, u32)> for SpecialCase {} +impl MaybeOverride<(i128, u32)> for SpecialCase {} +impl MaybeOverride<(u32, u32)> for SpecialCase {} +impl MaybeOverride<(u64, u32)> for SpecialCase {} +impl MaybeOverride<(u128, u32)> for SpecialCase {} diff --git a/library/compiler-builtins/libm-test/src/run_cfg.rs b/library/compiler-builtins/libm-test/src/run_cfg.rs index 63cb6910d0597..2b42d581b4c9f 100644 --- a/library/compiler-builtins/libm-test/src/run_cfg.rs +++ b/library/compiler-builtins/libm-test/src/run_cfg.rs @@ -5,7 +5,7 @@ use std::sync::LazyLock; use std::{env, fmt, str}; use crate::generate::random::{SEED, SEED_ENV}; -use crate::{BaseName, Group, Identifier, test_log}; +use crate::{BaseName, Group, Identifier, Ty, test_log}; /// The environment variable indicating which extensive tests should be run. pub const EXTENSIVE_ENV: &str = "LIBM_EXTENSIVE_TESTS"; @@ -361,6 +361,22 @@ where "requested argnum {argnum} of only {argcount} args" ); + // Shift operations can have UB if the shift value exceeds their range + if matches!( + ctx.base_name, + BaseName::Ashl | BaseName::Ashr | BaseName::Lshr + ) && argnum == 1 + { + let max = match ctx.fn_ident.math_op().rust_sig.args[0] { + Ty::U32 | Ty::I32 => 31, + Ty::U64 | Ty::I64 => 63, + Ty::U128 | Ty::I128 => 127, + ty => panic!("unexpected type {ty}"), + }; + + return Some(map_range(0..=max)); + } + // Use the whole range for most functions. if !matches!(ctx.base_name, BaseName::Jn | BaseName::Yn) { return None; @@ -388,7 +404,14 @@ where GeneratorKind::List => unimplemented!("shoudn't need range for {:?}", ctx.gen_kind), }; - Some(I::try_from(*ret.start()).unwrap()..=I::try_from(*ret.end()).unwrap()) + Some(map_range(ret)) +} + +fn map_range(r: RangeInclusive) -> RangeInclusive +where + I: TryFrom, +{ + I::try_from(*r.start()).unwrap()..=I::try_from(*r.end()).unwrap() } /// For domain tests, limit how many asymptotes or specified check points we test. diff --git a/library/compiler-builtins/libm-test/src/test_traits.rs b/library/compiler-builtins/libm-test/src/test_traits.rs index 1f0baf701bd02..fb13573f8a37e 100644 --- a/library/compiler-builtins/libm-test/src/test_traits.rs +++ b/library/compiler-builtins/libm-test/src/test_traits.rs @@ -249,7 +249,7 @@ where Ok(()) } -impl_int!(u16, i16, u32, i32, u64, i64, u128, i128); +impl_int!(u16, i16, u32, i32, u64, i64, u128, i128, usize); /* trait implementations for floats */ From c80dab667934dd6a63b3f89ec50b4a799aaae808 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Wed, 25 Mar 2026 04:08:19 -0500 Subject: [PATCH 033/183] test: Cover compiler-builtins integer arithmetic in libm-test Add the following to the test infrastructure: * `__rust_i128_add` * `__rust_i128_sub` * `__rust_u128_add` * `__rust_u128_sub` * `__rust_i128_addo` * `__rust_i128_subo` * `__rust_u128_addo` * `__rust_u128_subo` * `__muldi3` * `__multi3` * `__mulosi4` * `__mulodi4` * `__muloti4` * `__rust_u128_mulo` * `__divsi3` * `__divdi3` * `__divti3` * `__modsi3` * `__moddi3` * `__modti3` * `__divmodsi4` * `__divmoddi4` * `__divmodti4` * `__udivsi3` * `__udivdi3` * `__udivti3` * `__umodsi3` * `__umoddi3` * `__umodti3` * `__udivmodsi4` * `__udivmoddi4` * `__udivmodti4` --- .../crates/libm-macros/src/shared.rs | 151 +++++++++++ .../compiler-builtins/crates/util/src/main.rs | 16 +- .../libm-test/src/builtins_wrapper.rs | 73 ++++++ .../compiler-builtins/libm-test/src/domain.rs | 9 + .../libm-test/src/generate/case_list.rs | 130 ++++++++++ .../libm-test/src/generate/edge_cases.rs | 21 +- .../libm-test/src/generate/random.rs | 22 +- .../libm-test/src/generate/spaced.rs | 36 ++- .../libm-test/src/mpfloat.rs | 234 +++++++++++++++++- .../libm-test/src/precision.rs | 33 ++- .../libm-test/src/test_traits.rs | 16 ++ 11 files changed, 715 insertions(+), 26 deletions(-) diff --git a/library/compiler-builtins/crates/libm-macros/src/shared.rs b/library/compiler-builtins/crates/libm-macros/src/shared.rs index 716736fa1aeec..9a22d199536c0 100644 --- a/library/compiler-builtins/crates/libm-macros/src/shared.rs +++ b/library/compiler-builtins/crates/libm-macros/src/shared.rs @@ -595,6 +595,157 @@ const ALL_OPERATIONS_NESTED: &[NestedOp] = &[ fn_list: &["itof_u128_f128"], scope: OpScope::BuiltinsPublic, }, + /* int arithmetic */ + NestedOp { + rust_sig: Signature { + args: &[Ty::I32, Ty::I32], + returns: &[Ty::I32], + }, + c_sig: None, + fn_list: &["idiv_i32", "imod_i32"], + scope: OpScope::BuiltinsPublic, + }, + NestedOp { + rust_sig: Signature { + args: &[Ty::I32, Ty::I32], + returns: &[Ty::I32, Ty::I32], + }, + c_sig: None, + fn_list: &["idivmod_i32"], + scope: OpScope::BuiltinsPublic, + }, + NestedOp { + rust_sig: Signature { + args: &[Ty::I32, Ty::I32], + returns: &[Ty::I32, Ty::Bool], + }, + c_sig: None, + fn_list: &["imulo_i32"], + scope: OpScope::BuiltinsPublic, + }, + NestedOp { + rust_sig: Signature { + args: &[Ty::U32, Ty::U32], + returns: &[Ty::U32], + }, + c_sig: None, + fn_list: &["idiv_u32", "imod_u32"], + scope: OpScope::BuiltinsPublic, + }, + NestedOp { + rust_sig: Signature { + args: &[Ty::U32, Ty::U32], + returns: &[Ty::U32, Ty::U32], + }, + c_sig: None, + fn_list: &["idivmod_u32"], + scope: OpScope::BuiltinsPublic, + }, + NestedOp { + rust_sig: Signature { + args: &[Ty::I64, Ty::I64], + returns: &[Ty::I64], + }, + c_sig: None, + fn_list: &["idiv_i64", "imod_i64"], + scope: OpScope::BuiltinsPublic, + }, + NestedOp { + rust_sig: Signature { + args: &[Ty::I64, Ty::I64], + returns: &[Ty::I64, Ty::I64], + }, + c_sig: None, + fn_list: &["idivmod_i64"], + scope: OpScope::BuiltinsPublic, + }, + NestedOp { + rust_sig: Signature { + args: &[Ty::U64, Ty::U64], + returns: &[Ty::U64], + }, + c_sig: None, + fn_list: &["idiv_u64", "imod_u64", "imul_u64"], + scope: OpScope::BuiltinsPublic, + }, + NestedOp { + rust_sig: Signature { + args: &[Ty::U64, Ty::U64], + returns: &[Ty::U64, Ty::U64], + }, + c_sig: None, + fn_list: &["idivmod_u64"], + scope: OpScope::BuiltinsPublic, + }, + NestedOp { + rust_sig: Signature { + args: &[Ty::I64, Ty::I64], + returns: &[Ty::I64, Ty::Bool], + }, + c_sig: None, + fn_list: &["imulo_i64"], + scope: OpScope::BuiltinsPublic, + }, + NestedOp { + rust_sig: Signature { + args: &[Ty::I128, Ty::I128], + returns: &[Ty::I128], + }, + c_sig: None, + fn_list: &[ + "iadd_i128", + "idiv_i128", + "imod_i128", + "imul_i128", + "isub_i128", + ], + scope: OpScope::BuiltinsPublic, + }, + NestedOp { + rust_sig: Signature { + args: &[Ty::I128, Ty::I128], + returns: &[Ty::I128, Ty::I128], + }, + c_sig: None, + fn_list: &["idivmod_i128"], + scope: OpScope::BuiltinsPublic, + }, + NestedOp { + rust_sig: Signature { + args: &[Ty::I128, Ty::I128], + returns: &[Ty::I128, Ty::Bool], + }, + c_sig: None, + fn_list: &["iaddo_i128", "imulo_i128", "isubo_i128"], + scope: OpScope::BuiltinsPublic, + }, + NestedOp { + rust_sig: Signature { + args: &[Ty::U128, Ty::U128], + returns: &[Ty::U128], + }, + c_sig: None, + fn_list: &["iadd_u128", "idiv_u128", "imod_u128", "isub_u128"], + scope: OpScope::BuiltinsPublic, + }, + NestedOp { + rust_sig: Signature { + args: &[Ty::U128, Ty::U128], + returns: &[Ty::U128, Ty::U128], + }, + c_sig: None, + fn_list: &["idivmod_u128"], + scope: OpScope::BuiltinsPublic, + }, + NestedOp { + rust_sig: Signature { + args: &[Ty::U128, Ty::U128], + returns: &[Ty::U128, Ty::Bool], + }, + c_sig: None, + fn_list: &["iaddo_u128", "imulo_u128", "isubo_u128"], + scope: OpScope::BuiltinsPublic, + }, /* int shifts */ NestedOp { rust_sig: Signature { diff --git a/library/compiler-builtins/crates/util/src/main.rs b/library/compiler-builtins/crates/util/src/main.rs index 04fb090a81ff5..dbeb923364db5 100644 --- a/library/compiler-builtins/crates/util/src/main.rs +++ b/library/compiler-builtins/crates/util/src/main.rs @@ -310,7 +310,7 @@ impl_parse_tuple!(f64); impl_parse_tuple_via_rug!(f128); macro_rules! impl_parse_tuple_int { - ($ty:ty) => { + (@skip_u32 $ty:ty) => { impl ParseTuple for ($ty,) { fn parse(input: &[&str]) -> Self { assert_eq!(input.len(), 1, "expected a single argument, got {input:?}"); @@ -318,7 +318,7 @@ macro_rules! impl_parse_tuple_int { } } - impl ParseTuple for ($ty, u32) { + impl ParseTuple for ($ty, $ty) { fn parse(input: &[&str]) -> Self { assert_eq!(input.len(), 2, "expected two arguments, got {input:?}"); (parse(input, 0), parse(input, 1)) @@ -332,12 +332,22 @@ macro_rules! impl_parse_tuple_int { } } }; + ($ty:ty) => { + impl_parse_tuple_int!(@skip_u32 $ty); + + impl ParseTuple for ($ty, u32) { + fn parse(input: &[&str]) -> Self { + assert_eq!(input.len(), 2, "expected two arguments, got {input:?}"); + (parse(input, 0), parse(input, 1)) + } + } + }; } impl_parse_tuple_int!(i32); impl_parse_tuple_int!(i64); impl_parse_tuple_int!(i128); -impl_parse_tuple_int!(u32); +impl_parse_tuple_int!(@skip_u32 u32); impl_parse_tuple_int!(u64); impl_parse_tuple_int!(u128); diff --git a/library/compiler-builtins/libm-test/src/builtins_wrapper.rs b/library/compiler-builtins/libm-test/src/builtins_wrapper.rs index 9fac5e78f9642..ce517148b9ca3 100644 --- a/library/compiler-builtins/libm-test/src/builtins_wrapper.rs +++ b/library/compiler-builtins/libm-test/src/builtins_wrapper.rs @@ -58,6 +58,43 @@ macro_rules! cb_op { compiler_builtins::float::$mod::$cb_name(a, b) >= 0 } }; + (@int_binop_oflow $ty:ty, $mod:ident, $cb_name:ident, $new_name:ident) => { + pub fn $new_name(a: $ty, b: $ty) -> ($ty, bool) { + let mut oflow = 0; + let res = compiler_builtins::int::$mod::$cb_name(a, b, &mut oflow); + (res, oflow != 0) + } + }; + + // Make division by 0 well-defined so testing is easier. + (@int_div $ty:ty, $mod:ident, $cb_name:ident, $new_name:ident) => { + pub fn $new_name(a: $ty, b: $ty) -> $ty { + if b == 0 { + return <$ty>::MIN; + } + compiler_builtins::int::$mod::$cb_name(a, b) + } + }; + (@int_divmod $ty:ty, $mod:ident, $cb_name:ident, $new_name:ident) => { + pub fn $new_name(a: $ty, b: $ty) -> ($ty, $ty) { + if b == 0 { + return (<$ty>::MIN, <$ty>::MIN); + } + let mut rem = 0; + let div = compiler_builtins::int::$mod::$cb_name(a, b, &mut rem); + (div, rem) + } + }; + (@int_udivmod $ty:ty, $mod:ident, $cb_name:ident, $new_name:ident) => { + pub fn $new_name(a: $ty, b: $ty) -> ($ty, $ty) { + if b == 0 { + return (<$ty>::MIN, <$ty>::MIN); + } + let mut rem = 0; + let div = compiler_builtins::int::$mod::$cb_name(a, b, Some(&mut rem)); + (div, rem) + } + }; } #[cfg(f16_enabled)] @@ -219,6 +256,42 @@ cb_op!(conv, __floatuntitf, itof_u128_f128, (a: u128) -> f128); /* int ops */ +cb_op!(@int addsub, __rust_i128_add, iadd_i128, (a: i128, b: i128) -> i128); +cb_op!(@int addsub, __rust_i128_sub, isub_i128, (a: i128, b: i128) -> i128); +cb_op!(@int addsub, __rust_u128_add, iadd_u128, (a: u128, b: u128) -> u128); +cb_op!(@int addsub, __rust_u128_sub, isub_u128, (a: u128, b: u128) -> u128); +cb_op!(@int_binop_oflow i128, addsub, __rust_i128_addo, iaddo_i128); +cb_op!(@int_binop_oflow i128, addsub, __rust_i128_subo, isubo_i128); +cb_op!(@int_binop_oflow u128, addsub, __rust_u128_addo, iaddo_u128); +cb_op!(@int_binop_oflow u128, addsub, __rust_u128_subo, isubo_u128); + +cb_op!(@int mul, __muldi3, imul_u64, (a: u64, b: u64) -> u64); +cb_op!(@int mul, __multi3, imul_i128, (a: i128, b: i128) -> i128); +cb_op!(@int_binop_oflow i32, mul, __mulosi4, imulo_i32); +cb_op!(@int_binop_oflow i64, mul, __mulodi4, imulo_i64); +cb_op!(@int_binop_oflow i128, mul, __muloti4, imulo_i128); +cb_op!(@int_binop_oflow u128, mul, __rust_u128_mulo, imulo_u128); + +cb_op!(@int_div i32, sdiv, __divsi3, idiv_i32); +cb_op!(@int_div i64, sdiv, __divdi3, idiv_i64); +cb_op!(@int_div i128, sdiv, __divti3, idiv_i128); +cb_op!(@int_div i32, sdiv, __modsi3, imod_i32); +cb_op!(@int_div i64, sdiv, __moddi3, imod_i64); +cb_op!(@int_div i128, sdiv, __modti3, imod_i128); +cb_op!(@int_divmod i32, sdiv, __divmodsi4, idivmod_i32); +cb_op!(@int_divmod i64, sdiv, __divmoddi4, idivmod_i64); +cb_op!(@int_divmod i128, sdiv, __divmodti4, idivmod_i128); + +cb_op!(@int_div u32, udiv, __udivsi3, idiv_u32); +cb_op!(@int_div u64, udiv, __udivdi3, idiv_u64); +cb_op!(@int_div u128, udiv, __udivti3, idiv_u128); +cb_op!(@int_div u32, udiv, __umodsi3, imod_u32); +cb_op!(@int_div u64, udiv, __umoddi3, imod_u64); +cb_op!(@int_div u128, udiv, __umodti3, imod_u128); +cb_op!(@int_udivmod u32, udiv, __udivmodsi4, idivmod_u32); +cb_op!(@int_udivmod u64, udiv, __udivmoddi4, idivmod_u64); +cb_op!(@int_udivmod u128, udiv, __udivmodti4, idivmod_u128); + cb_op!(@int shift, __ashlsi3, ashl_u32, (a: u32, b: u32) -> u32); cb_op!(@int shift, __ashldi3, ashl_u64, (a: u64, b: u32) -> u64); cb_op!(@int shift, __ashlti3, ashl_u128, (a: u128, b: u32) -> u128); diff --git a/library/compiler-builtins/libm-test/src/domain.rs b/library/compiler-builtins/libm-test/src/domain.rs index c2e4317086f18..0ae105f4a02d2 100644 --- a/library/compiler-builtins/libm-test/src/domain.rs +++ b/library/compiler-builtins/libm-test/src/domain.rs @@ -247,6 +247,15 @@ pub fn get_domain( BaseName::Itof => &EitherPrim::UNBOUNDED1[..], // Integer ops + BaseName::Iadd => &EitherPrim::UNBOUNDED2[..], + BaseName::Iaddo => &EitherPrim::UNBOUNDED2[..], + BaseName::Isub => &EitherPrim::UNBOUNDED2[..], + BaseName::Isubo => &EitherPrim::UNBOUNDED2[..], + BaseName::Imul => &EitherPrim::UNBOUNDED2[..], + BaseName::Imulo => &EitherPrim::UNBOUNDED2[..], + BaseName::Idiv => &EitherPrim::UNBOUNDED2[..], + BaseName::Imod => &EitherPrim::UNBOUNDED2[..], + BaseName::Idivmod => &EitherPrim::UNBOUNDED2[..], // Shifts technically aren't unbounded, but its range is restricted elsewhere in // our test generators. BaseName::Ashl => &EitherPrim::UNBOUNDED2[..], diff --git a/library/compiler-builtins/libm-test/src/generate/case_list.rs b/library/compiler-builtins/libm-test/src/generate/case_list.rs index f6c58dd1ce546..c85608eb9900d 100644 --- a/library/compiler-builtins/libm-test/src/generate/case_list.rs +++ b/library/compiler-builtins/libm-test/src/generate/case_list.rs @@ -468,6 +468,136 @@ fn itof_u128_f128_cases() -> Vec> { vec![] } +/* int arithmetic */ + +fn iadd_i128_cases() -> Vec> { + vec![] +} + +fn iadd_u128_cases() -> Vec> { + vec![] +} + +fn iaddo_i128_cases() -> Vec> { + vec![] +} + +fn iaddo_u128_cases() -> Vec> { + vec![] +} + +fn isub_i128_cases() -> Vec> { + vec![] +} + +fn isub_u128_cases() -> Vec> { + vec![] +} + +fn isubo_i128_cases() -> Vec> { + vec![] +} + +fn isubo_u128_cases() -> Vec> { + vec![] +} + +fn idiv_i128_cases() -> Vec> { + vec![] +} + +fn idiv_i32_cases() -> Vec> { + vec![] +} + +fn idiv_i64_cases() -> Vec> { + vec![] +} + +fn idiv_u128_cases() -> Vec> { + vec![] +} + +fn idiv_u32_cases() -> Vec> { + vec![] +} + +fn idiv_u64_cases() -> Vec> { + vec![] +} + +fn idivmod_i128_cases() -> Vec> { + vec![] +} + +fn idivmod_i32_cases() -> Vec> { + vec![] +} + +fn idivmod_i64_cases() -> Vec> { + vec![] +} + +fn idivmod_u128_cases() -> Vec> { + vec![] +} + +fn idivmod_u32_cases() -> Vec> { + vec![] +} + +fn idivmod_u64_cases() -> Vec> { + vec![] +} + +fn imod_i128_cases() -> Vec> { + vec![] +} + +fn imod_i32_cases() -> Vec> { + vec![] +} + +fn imod_i64_cases() -> Vec> { + vec![] +} + +fn imod_u128_cases() -> Vec> { + vec![] +} + +fn imod_u32_cases() -> Vec> { + vec![] +} + +fn imod_u64_cases() -> Vec> { + vec![] +} + +fn imul_i128_cases() -> Vec> { + vec![] +} + +fn imul_u64_cases() -> Vec> { + vec![] +} + +fn imulo_i128_cases() -> Vec> { + vec![] +} + +fn imulo_i32_cases() -> Vec> { + vec![] +} + +fn imulo_i64_cases() -> Vec> { + vec![] +} + +fn imulo_u128_cases() -> Vec> { + vec![] +} + /* int shifts */ fn ashl_u32_cases() -> Vec> { diff --git a/library/compiler-builtins/libm-test/src/generate/edge_cases.rs b/library/compiler-builtins/libm-test/src/generate/edge_cases.rs index 761b5d92c97cf..84ef5a2a36b43 100644 --- a/library/compiler-builtins/libm-test/src/generate/edge_cases.rs +++ b/library/compiler-builtins/libm-test/src/generate/edge_cases.rs @@ -315,7 +315,7 @@ impl_edge_case_input!(f64); impl_edge_case_input!(f128); macro_rules! impl_edge_case_input_int { - ($ity:ty) => { + (@skip_u32 $ity:ty) => { impl EdgeCaseInput for ($ity,) where Op: MathOp, @@ -327,6 +327,23 @@ macro_rules! impl_edge_case_input_int { } } + impl EdgeCaseInput for ($ity, $ity) + where + Op: MathOp, + { + fn get_cases(ctx: &CheckCtx) -> (impl Iterator, u64) { + let (iter0, steps0) = int_edge_cases(ctx, 0); + let (iter1, steps1) = int_edge_cases(ctx, 1); + let iter = + iter0.flat_map(move |first| iter1.clone().map(move |second| (first, second))); + let count = steps0.checked_mul(steps1).unwrap(); + (iter, count) + } + } + }; + ($ity:ty) => { + impl_edge_case_input_int!(@skip_u32 $ity); + impl EdgeCaseInput for ($ity, u32) where Op: MathOp, @@ -346,7 +363,7 @@ macro_rules! impl_edge_case_input_int { impl_edge_case_input_int!(i32); impl_edge_case_input_int!(i64); impl_edge_case_input_int!(i128); -impl_edge_case_input_int!(u32); +impl_edge_case_input_int!(@skip_u32 u32); impl_edge_case_input_int!(u64); impl_edge_case_input_int!(u128); diff --git a/library/compiler-builtins/libm-test/src/generate/random.rs b/library/compiler-builtins/libm-test/src/generate/random.rs index c621d631490c6..6ce0df458d493 100644 --- a/library/compiler-builtins/libm-test/src/generate/random.rs +++ b/library/compiler-builtins/libm-test/src/generate/random.rs @@ -120,7 +120,7 @@ impl_random_input!(f64); impl_random_input!(f128); macro_rules! impl_random_input_int { - ($ity:ty) => { + (@skip_u32 $ity:ty) => { impl RandomInput for ($ity,) { fn get_cases(ctx: &CheckCtx) -> (impl Iterator, u64) { let count = iteration_count(ctx, 0); @@ -130,11 +130,27 @@ macro_rules! impl_random_input_int { } } + impl RandomInput for ($ity, $ity) { + fn get_cases(ctx: &CheckCtx) -> (impl Iterator, u64) { + let count0 = iteration_count(ctx, 0); + let count1 = iteration_count(ctx, 1); + let range0 = int_range::<$ity>(ctx, 0).unwrap_or(full_range()); + let range1 = int_range::<$ity>(ctx, 1).unwrap_or(full_range()); + let iter = random_ints(count0, range0).flat_map(move |f1: $ity| { + random_ints(count1, range1.clone()).map(move |f2: $ity| (f1, f2)) + }); + (iter, count0 * count1) + } + } + }; + ($ity:ty) => { + impl_random_input_int!(@skip_u32 $ity); + impl RandomInput for ($ity, u32) { fn get_cases(ctx: &CheckCtx) -> (impl Iterator, u64) { let count0 = iteration_count(ctx, 0); let count1 = iteration_count(ctx, 1); - let range0 = int_range::<$ity>(ctx, 1).unwrap_or(full_range()); + let range0 = int_range::<$ity>(ctx, 0).unwrap_or(full_range()); let range1 = int_range::(ctx, 1).unwrap_or(full_range()); let iter = random_ints(count0, range0).flat_map(move |f1: $ity| { random_ints(count1, range1.clone()).map(move |f2: u32| (f1, f2)) @@ -148,7 +164,7 @@ macro_rules! impl_random_input_int { impl_random_input_int!(i32); impl_random_input_int!(i64); impl_random_input_int!(i128); -impl_random_input_int!(u32); +impl_random_input_int!(@skip_u32 u32); impl_random_input_int!(u64); impl_random_input_int!(u128); diff --git a/library/compiler-builtins/libm-test/src/generate/spaced.rs b/library/compiler-builtins/libm-test/src/generate/spaced.rs index dd5c728ca2849..a825fe4c323b2 100644 --- a/library/compiler-builtins/libm-test/src/generate/spaced.rs +++ b/library/compiler-builtins/libm-test/src/generate/spaced.rs @@ -254,7 +254,7 @@ impl_spaced_input!(f64); impl_spaced_input!(f128); macro_rules! impl_spaced_input_int { - ($ity:ty) => { + (@skip_u32 $ity:ty) => { impl SpacedInput for ($ity,) where Op: MathOp, @@ -276,6 +276,38 @@ macro_rules! impl_spaced_input_int { } } + impl SpacedInput for ($ity, $ity) + where + Op: MathOp, + { + fn get_cases(ctx: &CheckCtx) -> (impl Iterator, u64) { + let range0 = int_range(ctx, 0).unwrap_or(full_range()); + let range1 = int_range(ctx, 1).unwrap_or(full_range()); + let max_steps0 = iteration_count(ctx, 0); + let max_steps1 = iteration_count(ctx, 0); + match value_count_int::>() { + Some(count) if count <= max_steps0 && count < max_steps1 => { + let iter = range0.flat_map(move |first| { + range1.clone().map(move |second| (first, second)) + }); + (EitherIter::A(iter), count.checked_mul(count).unwrap()) + } + _ => { + let (iter0, steps0) = linear_ints::>(range0, max_steps0); + let (iter1, steps1) = linear_ints::>(range1, max_steps1); + let iter = iter0.flat_map(move |first| { + iter1.clone().map(move |second| (first, second)) + }); + let count = steps0.checked_mul(steps1).unwrap(); + (EitherIter::B(iter), count) + } + } + } + } + }; + ($ity:ty) => { + impl_spaced_input_int!(@skip_u32 $ity); + impl SpacedInput for ($ity, u32) where Op: MathOp, @@ -310,7 +342,7 @@ macro_rules! impl_spaced_input_int { impl_spaced_input_int!(i32); impl_spaced_input_int!(i64); impl_spaced_input_int!(i128); -impl_spaced_input_int!(u32); +impl_spaced_input_int!(@skip_u32 u32); impl_spaced_input_int!(u64); impl_spaced_input_int!(u128); diff --git a/library/compiler-builtins/libm-test/src/mpfloat.rs b/library/compiler-builtins/libm-test/src/mpfloat.rs index dd439e1d7b012..c4f1ca193e589 100644 --- a/library/compiler-builtins/libm-test/src/mpfloat.rs +++ b/library/compiler-builtins/libm-test/src/mpfloat.rs @@ -6,7 +6,7 @@ use std::cmp::Ordering; use rug::Assign; -use rug::az::{self, Az, CheckedCast, WrappingAs}; +use rug::az::{self, Az, CheckedCast, OverflowingCast, WrappingAs}; use rug::float::Round::Nearest; use rug::ops::{ AddAssignRound, DivAssignRound, MulAssignRound, PowAssignRound, RemAssignRound, SubAssignRound, @@ -215,10 +215,42 @@ libm_macros::for_each_function! { gtf16, gtf32, gtf64, + iadd_i128, + iadd_u128, + iaddo_i128, + iaddo_u128, + idiv_i128, + idiv_i32, + idiv_i64, + idiv_u128, + idiv_u32, + idiv_u64, + idivmod_i128, + idivmod_i32, + idivmod_i64, + idivmod_u128, + idivmod_u32, + idivmod_u64, ilogb, ilogbf, ilogbf128, ilogbf16, + imod_i128, + imod_i32, + imod_i64, + imod_u128, + imod_u32, + imod_u64, + imul_i128, + imul_u64, + imulo_i128, + imulo_i32, + imulo_i64, + imulo_u128, + isub_i128, + isub_u128, + isubo_i128, + isubo_u128, itof_i128_f128, itof_i128_f32, itof_i128_f64, @@ -1038,6 +1070,77 @@ impl MpOp for crate::op::nextafterf::Routine { } macro_rules! impl_int_ops { + ($ity:ty) => { + paste::paste! { + impl MpOp for crate::op::[]::Routine { + type MpTy = MpInt; + + fn new_mp() -> Self::MpTy { + MpInt::new() + } + + fn run(this: &mut Self::MpTy, input: Self::RustArgs) -> Self::RustRet { + if input.1 == 0 { + // Make divide by 0 well-defined to match our wrappers. + return <$ity>::MIN; + } + this.assign(input.0); + *this /= input.1; + (&*this).wrapping_as::() + } + } + + impl MpOp for crate::op::[]::Routine { + type MpTy = MpInt; + + fn new_mp() -> Self::MpTy { + MpInt::new() + } + + fn run(this: &mut Self::MpTy, input: Self::RustArgs) -> Self::RustRet { + if input.1 == 0 { + // Make divide by 0 well-defined to match our wrappers. + return <$ity>::MIN; + } + this.assign(input.0); + *this %= input.1; + (&*this).wrapping_as::() + } + } + + impl MpOp for crate::op::[]::Routine { + type MpTy = (MpInt, MpInt); + + fn new_mp() -> Self::MpTy { + (MpInt::new(), MpInt::new()) + } + + fn run(this: &mut Self::MpTy, input: Self::RustArgs) -> Self::RustRet { + if input.1 == 0 { + // Make divide by 0 well-defined to match our wrappers. + return (<$ity>::MIN, <$ity>::MIN); + } + this.0.assign(input.0); + this.1.assign(input.1); + this.0.div_rem_mut(&mut this.1); + ( + (&this.0).wrapping_as::>(), + (&this.1).wrapping_as::>(), + ) + } + } + } + }; +} + +impl_int_ops!(i32); +impl_int_ops!(i64); +impl_int_ops!(i128); +impl_int_ops!(u32); +impl_int_ops!(u64); +impl_int_ops!(u128); + +macro_rules! impl_unsigned_int_ops { ($ity:ty) => { paste::paste! { impl MpOp for crate::op::[]::Routine { @@ -1099,9 +1202,9 @@ macro_rules! impl_int_ops { }; } -impl_int_ops!(u32); -impl_int_ops!(u64); -impl_int_ops!(u128); +impl_unsigned_int_ops!(u32); +impl_unsigned_int_ops!(u64); +impl_unsigned_int_ops!(u128); macro_rules! impl_signed_int_ops { ($ity:ty) => { @@ -1117,7 +1220,21 @@ macro_rules! impl_signed_int_ops { assert!(input.1 < Arg0::::BITS, "got UB shift {}", input.1); this.assign(input.0); *this >>= input.1; - (&*this).wrapping_as::>() + (&*this).wrapping_as::() + } + } + + impl MpOp for crate::op::[]::Routine { + type MpTy = MpInt; + + fn new_mp() -> Self::MpTy { + MpInt::new() + } + + fn run(this: &mut Self::MpTy, input: Self::RustArgs) -> Self::RustRet { + this.assign(input.0); + *this *= input.1; + (&*this).overflowing_cast() } } } @@ -1127,3 +1244,110 @@ macro_rules! impl_signed_int_ops { impl_signed_int_ops!(i32); impl_signed_int_ops!(i64); impl_signed_int_ops!(i128); + +macro_rules! impl_u128_i128_int_ops { + ($ity:ty) => { + paste::paste! { + impl MpOp for crate::op::[]::Routine { + type MpTy = MpInt; + + fn new_mp() -> Self::MpTy { + MpInt::new() + } + + fn run(this: &mut Self::MpTy, input: Self::RustArgs) -> Self::RustRet { + this.assign(input.0); + *this += input.1; + (&*this).wrapping_as::() + } + } + + impl MpOp for crate::op::[]::Routine { + type MpTy = MpInt; + + fn new_mp() -> Self::MpTy { + MpInt::new() + } + + fn run(this: &mut Self::MpTy, input: Self::RustArgs) -> Self::RustRet { + this.assign(input.0); + *this -= input.1; + (&*this).wrapping_as::() + } + } + + impl MpOp for crate::op::[]::Routine { + type MpTy = MpInt; + + fn new_mp() -> Self::MpTy { + MpInt::new() + } + + fn run(this: &mut Self::MpTy, input: Self::RustArgs) -> Self::RustRet { + this.assign(input.0); + *this += input.1; + (&*this).overflowing_cast() + } + } + + impl MpOp for crate::op::[]::Routine { + type MpTy = MpInt; + + fn new_mp() -> Self::MpTy { + MpInt::new() + } + + fn run(this: &mut Self::MpTy, input: Self::RustArgs) -> Self::RustRet { + this.assign(input.0); + *this -= input.1; + (&*this).overflowing_cast() + } + } + } + }; +} + +impl_u128_i128_int_ops!(i128); +impl_u128_i128_int_ops!(u128); + +impl MpOp for crate::op::imul_u64::Routine { + type MpTy = MpInt; + + fn new_mp() -> Self::MpTy { + MpInt::new() + } + + fn run(this: &mut Self::MpTy, input: Self::RustArgs) -> Self::RustRet { + this.assign(input.0); + *this *= input.1; + (&*this).wrapping_as() + } +} + +impl MpOp for crate::op::imul_i128::Routine { + type MpTy = MpInt; + + fn new_mp() -> Self::MpTy { + MpInt::new() + } + + fn run(this: &mut Self::MpTy, input: Self::RustArgs) -> Self::RustRet { + this.assign(input.0); + *this *= input.1; + (&*this).wrapping_as() + } +} + +impl MpOp for crate::op::imulo_u128::Routine { + type MpTy = MpInt; + + fn new_mp() -> Self::MpTy { + MpInt::new() + } + + fn run(this: &mut Self::MpTy, input: Self::RustArgs) -> Self::RustRet { + this.assign(input.0); + *this *= input.1; + (&*this).overflowing_cast() + } +} diff --git a/library/compiler-builtins/libm-test/src/precision.rs b/library/compiler-builtins/libm-test/src/precision.rs index 56d4359e39c78..f6b31f6e329a3 100644 --- a/library/compiler-builtins/libm-test/src/precision.rs +++ b/library/compiler-builtins/libm-test/src/precision.rs @@ -24,19 +24,23 @@ pub fn default_ulp(ctx: &CheckCtx) -> Option { Bn::Powi => 1000, // Operations that only return non-float results - Bn::Eq - | Bn::Ne - | Bn::Gt - | Bn::Ge - | Bn::Lt - | Bn::Le - | Bn::Unord - | Bn::Ilogb - | Bn::Ashl + Bn::Eq | Bn::Ne | Bn::Gt | Bn::Ge | Bn::Lt | Bn::Le | Bn::Unord | Bn::Ilogb => return None, + + // Integer ops + Bn::Ashl | Bn::Ashr | Bn::Lshr | Bn::LeadingZeros - | Bn::TrailingZeros => return None, + | Bn::TrailingZeros + | Bn::Iadd + | Bn::Iaddo + | Bn::Isub + | Bn::Isubo + | Bn::Imul + | Bn::Imulo + | Bn::Idiv + | Bn::Imod + | Bn::Idivmod => return None, // Convrsion operations must be precise. Bn::Extend | Bn::Narrow | Bn::Ftoi | Bn::Itof => 0, @@ -556,9 +560,16 @@ impl MaybeOverride<(i128,)> for SpecialCase {} impl MaybeOverride<(u32,)> for SpecialCase {} impl MaybeOverride<(u64,)> for SpecialCase {} impl MaybeOverride<(u128,)> for SpecialCase {} + +impl MaybeOverride<(i32, i32)> for SpecialCase {} +impl MaybeOverride<(i64, i64)> for SpecialCase {} +impl MaybeOverride<(i128, i128)> for SpecialCase {} +impl MaybeOverride<(u32, u32)> for SpecialCase {} +impl MaybeOverride<(u64, u64)> for SpecialCase {} +impl MaybeOverride<(u128, u128)> for SpecialCase {} + impl MaybeOverride<(i32, u32)> for SpecialCase {} impl MaybeOverride<(i64, u32)> for SpecialCase {} impl MaybeOverride<(i128, u32)> for SpecialCase {} -impl MaybeOverride<(u32, u32)> for SpecialCase {} impl MaybeOverride<(u64, u32)> for SpecialCase {} impl MaybeOverride<(u128, u32)> for SpecialCase {} diff --git a/library/compiler-builtins/libm-test/src/test_traits.rs b/library/compiler-builtins/libm-test/src/test_traits.rs index fb13573f8a37e..657190d80d710 100644 --- a/library/compiler-builtins/libm-test/src/test_traits.rs +++ b/library/compiler-builtins/libm-test/src/test_traits.rs @@ -428,6 +428,22 @@ macro_rules! impl_tuples { } impl_tuples!( + (i32, i32); + (i64, i64); + (i128, i128); + + (u32, u32); + (u64, u64); + (u128, u128); + + (i32, bool); + (i64, bool); + (i128, bool); + + (u32, bool); + (u64, bool); + (u128, bool); + (f32, i32); (f64, i32); (f32, f32); From 693662d76077a1484ce66303aad0316781bb4797 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Wed, 25 Mar 2026 06:26:27 -0500 Subject: [PATCH 034/183] test: Add new functions to icount benchmarks --- .../libm-test/benches/icount.rs | 84 +++++++++++++++++++ 1 file changed, 84 insertions(+) diff --git a/library/compiler-builtins/libm-test/benches/icount.rs b/library/compiler-builtins/libm-test/benches/icount.rs index 294ee9230821a..0362325fabc67 100644 --- a/library/compiler-builtins/libm-test/benches/icount.rs +++ b/library/compiler-builtins/libm-test/benches/icount.rs @@ -255,6 +255,12 @@ main!( icount_bench_addf16_group, icount_bench_addf32_group, icount_bench_addf64_group, + icount_bench_ashl_u128_group, + icount_bench_ashl_u32_group, + icount_bench_ashl_u64_group, + icount_bench_ashr_i128_group, + icount_bench_ashr_i32_group, + icount_bench_ashr_i64_group, icount_bench_asin_group, icount_bench_asinf_group, icount_bench_asinh_group, @@ -351,6 +357,25 @@ main!( icount_bench_frexpf128_group, icount_bench_frexpf16_group, icount_bench_frexpf_group, + icount_bench_ftoi_f128_i128_group, + icount_bench_ftoi_f128_i32_group, + icount_bench_ftoi_f128_i64_group, + icount_bench_ftoi_f128_u128_group, + icount_bench_ftoi_f128_u32_group, + icount_bench_ftoi_f128_u64_group, + icount_bench_ftoi_f32_i128_group, + icount_bench_ftoi_f32_i32_group, + icount_bench_ftoi_f32_i64_group, + icount_bench_ftoi_f32_u128_group, + icount_bench_ftoi_f32_u32_group, + icount_bench_ftoi_f32_u64_group, + icount_bench_ftoi_f64_i128_group, + icount_bench_ftoi_f64_i32_group, + icount_bench_ftoi_f64_i64_group, + icount_bench_ftoi_f64_u128_group, + icount_bench_ftoi_f64_u32_group, + icount_bench_ftoi_f64_u64_group, + icount_bench_gef128_group, icount_bench_gef128_group, icount_bench_gef16_group, icount_bench_gef32_group, @@ -361,10 +386,60 @@ main!( icount_bench_gtf64_group, icount_bench_hypot_group, icount_bench_hypotf_group, + icount_bench_iadd_i128_group, + icount_bench_iadd_u128_group, + icount_bench_iaddo_i128_group, + icount_bench_iaddo_u128_group, + icount_bench_idiv_i128_group, + icount_bench_idiv_i32_group, + icount_bench_idiv_i64_group, + icount_bench_idiv_u128_group, + icount_bench_idiv_u32_group, + icount_bench_idiv_u64_group, + icount_bench_idivmod_i128_group, + icount_bench_idivmod_i32_group, + icount_bench_idivmod_i64_group, + icount_bench_idivmod_u128_group, + icount_bench_idivmod_u32_group, + icount_bench_idivmod_u64_group, icount_bench_ilogb_group, icount_bench_ilogbf128_group, icount_bench_ilogbf16_group, icount_bench_ilogbf_group, + icount_bench_imod_i128_group, + icount_bench_imod_i32_group, + icount_bench_imod_i64_group, + icount_bench_imod_u128_group, + icount_bench_imod_u32_group, + icount_bench_imod_u64_group, + icount_bench_imul_i128_group, + icount_bench_imul_u64_group, + icount_bench_imulo_i128_group, + icount_bench_imulo_i32_group, + icount_bench_imulo_i64_group, + icount_bench_imulo_u128_group, + icount_bench_isub_i128_group, + icount_bench_isub_u128_group, + icount_bench_isubo_i128_group, + icount_bench_isubo_u128_group, + icount_bench_itof_i128_f128_group, + icount_bench_itof_i128_f32_group, + icount_bench_itof_i128_f64_group, + icount_bench_itof_i32_f128_group, + icount_bench_itof_i32_f32_group, + icount_bench_itof_i32_f64_group, + icount_bench_itof_i64_f128_group, + icount_bench_itof_i64_f32_group, + icount_bench_itof_i64_f64_group, + icount_bench_itof_u128_f128_group, + icount_bench_itof_u128_f32_group, + icount_bench_itof_u128_f64_group, + icount_bench_itof_u32_f128_group, + icount_bench_itof_u32_f32_group, + icount_bench_itof_u32_f64_group, + icount_bench_itof_u64_f128_group, + icount_bench_itof_u64_f32_group, + icount_bench_itof_u64_f64_group, icount_bench_j0_group, icount_bench_j0f_group, icount_bench_j1_group, @@ -375,6 +450,9 @@ main!( icount_bench_ldexpf128_group, icount_bench_ldexpf16_group, icount_bench_ldexpf_group, + icount_bench_leading_zeros_u128_group, + icount_bench_leading_zeros_u32_group, + icount_bench_leading_zeros_u64_group, icount_bench_lef128_group, icount_bench_lef16_group, icount_bench_lef32_group, @@ -391,6 +469,9 @@ main!( icount_bench_log2f_group, icount_bench_log_group, icount_bench_logf_group, + icount_bench_lshr_u128_group, + icount_bench_lshr_u32_group, + icount_bench_lshr_u64_group, icount_bench_ltf128_group, icount_bench_ltf16_group, icount_bench_ltf32_group, @@ -458,6 +539,9 @@ main!( icount_bench_tanhf_group, icount_bench_tgamma_group, icount_bench_tgammaf_group, + icount_bench_trailing_zeros_u128_group, + icount_bench_trailing_zeros_u32_group, + icount_bench_trailing_zeros_u64_group, icount_bench_trunc_group, icount_bench_truncf128_group, icount_bench_truncf16_group, From 378a812d5edb29c9cc80a097065c1c472493357d Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Wed, 25 Mar 2026 06:32:02 -0500 Subject: [PATCH 035/183] test: Switch to gungraun's new macro syntax --- .../builtins-test/benches/mem_icount.rs | 10 +- .../libm-test/benches/icount.rs | 650 +++++++++--------- 2 files changed, 331 insertions(+), 329 deletions(-) diff --git a/library/compiler-builtins/builtins-test/benches/mem_icount.rs b/library/compiler-builtins/builtins-test/benches/mem_icount.rs index 37595e8258436..7a3cad09b4044 100644 --- a/library/compiler-builtins/builtins-test/benches/mem_icount.rs +++ b/library/compiler-builtins/builtins-test/benches/mem_icount.rs @@ -118,7 +118,7 @@ mod mcpy { } } - library_benchmark_group!(name = memcpy; benchmarks = bench_cpy); + library_benchmark_group!(name = memcpy, benchmarks = [bench_cpy]); } mod mset { @@ -167,7 +167,7 @@ mod mset { } } - library_benchmark_group!(name = memset; benchmarks = bench_set); + library_benchmark_group!(name = memset, benchmarks = [bench_set]); } mod mcmp { @@ -235,7 +235,7 @@ mod mcmp { } } - library_benchmark_group!(name = memcmp; benchmarks = bench_cmp); + library_benchmark_group!(name = memcmp, benchmarks = [bench_cmp]); } mod mmove { @@ -489,7 +489,7 @@ mod mmove { } } - library_benchmark_group!(name = memmove; benchmarks = forward_move, backward_move); + library_benchmark_group!(name = memmove, benchmarks = [forward_move, backward_move]); } use mcmp::memcmp; @@ -497,4 +497,4 @@ use mcpy::memcpy; use mmove::memmove; use mset::memset; -main!(library_benchmark_groups = memcpy, memset, memcmp, memmove); +main!(library_benchmark_groups = [memcpy, memset, memcmp, memmove]); diff --git a/library/compiler-builtins/libm-test/benches/icount.rs b/library/compiler-builtins/libm-test/benches/icount.rs index 0362325fabc67..2fd46244deeef 100644 --- a/library/compiler-builtins/libm-test/benches/icount.rs +++ b/library/compiler-builtins/libm-test/benches/icount.rs @@ -231,331 +231,333 @@ fn icount_bench_print_hf128(x: f128) -> String { } library_benchmark_group!( - name = icount_bench_hf_print_group; - benchmarks = - icount_bench_print_hf16, - icount_bench_print_hf32, - icount_bench_print_hf64, - icount_bench_print_hf128 + name = icount_bench_hf_print_group, + benchmarks = [ + icount_bench_print_hf16, + icount_bench_print_hf32, + icount_bench_print_hf64, + icount_bench_print_hf128, + ] ); main!( - library_benchmark_groups = - // Benchmarks not related to public libm math - icount_bench_u128_group, - icount_bench_hf_parse_group, - icount_bench_hf_print_group, - // verify-apilist-start - // verify-sorted-start - icount_bench_acos_group, - icount_bench_acosf_group, - icount_bench_acosh_group, - icount_bench_acoshf_group, - icount_bench_addf128_group, - icount_bench_addf16_group, - icount_bench_addf32_group, - icount_bench_addf64_group, - icount_bench_ashl_u128_group, - icount_bench_ashl_u32_group, - icount_bench_ashl_u64_group, - icount_bench_ashr_i128_group, - icount_bench_ashr_i32_group, - icount_bench_ashr_i64_group, - icount_bench_asin_group, - icount_bench_asinf_group, - icount_bench_asinh_group, - icount_bench_asinhf_group, - icount_bench_atan2_group, - icount_bench_atan2f_group, - icount_bench_atan_group, - icount_bench_atanf_group, - icount_bench_atanh_group, - icount_bench_atanhf_group, - icount_bench_cbrt_group, - icount_bench_cbrtf_group, - icount_bench_ceil_group, - icount_bench_ceilf128_group, - icount_bench_ceilf16_group, - icount_bench_ceilf_group, - icount_bench_copysign_group, - icount_bench_copysignf128_group, - icount_bench_copysignf16_group, - icount_bench_copysignf_group, - icount_bench_cos_group, - icount_bench_cosf_group, - icount_bench_cosh_group, - icount_bench_coshf_group, - icount_bench_divf128_group, - icount_bench_divf32_group, - icount_bench_divf64_group, - icount_bench_eqf128_group, - icount_bench_eqf16_group, - icount_bench_eqf32_group, - icount_bench_eqf64_group, - icount_bench_erf_group, - icount_bench_erfc_group, - icount_bench_erfcf_group, - icount_bench_erff_group, - icount_bench_exp10_group, - icount_bench_exp10f_group, - icount_bench_exp2_group, - icount_bench_exp2f_group, - icount_bench_exp_group, - icount_bench_expf_group, - icount_bench_expm1_group, - icount_bench_expm1f_group, - icount_bench_extend_f16_f128_group, - icount_bench_extend_f16_f32_group, - icount_bench_extend_f16_f64_group, - icount_bench_extend_f32_f128_group, - icount_bench_extend_f32_f64_group, - icount_bench_extend_f64_f128_group, - icount_bench_fabs_group, - icount_bench_fabsf128_group, - icount_bench_fabsf16_group, - icount_bench_fabsf_group, - icount_bench_fdim_group, - icount_bench_fdimf128_group, - icount_bench_fdimf16_group, - icount_bench_fdimf_group, - icount_bench_floor_group, - icount_bench_floorf128_group, - icount_bench_floorf16_group, - icount_bench_floorf_group, - icount_bench_fma_group, - icount_bench_fmaf128_group, - icount_bench_fmaf_group, - icount_bench_fmax_group, - icount_bench_fmaxf128_group, - icount_bench_fmaxf16_group, - icount_bench_fmaxf_group, - icount_bench_fmaximum_group, - icount_bench_fmaximum_num_group, - icount_bench_fmaximum_numf128_group, - icount_bench_fmaximum_numf16_group, - icount_bench_fmaximum_numf_group, - icount_bench_fmaximumf128_group, - icount_bench_fmaximumf16_group, - icount_bench_fmaximumf_group, - icount_bench_fmin_group, - icount_bench_fminf128_group, - icount_bench_fminf16_group, - icount_bench_fminf_group, - icount_bench_fminimum_group, - icount_bench_fminimum_num_group, - icount_bench_fminimum_numf128_group, - icount_bench_fminimum_numf16_group, - icount_bench_fminimum_numf_group, - icount_bench_fminimumf128_group, - icount_bench_fminimumf16_group, - icount_bench_fminimumf_group, - icount_bench_fmod_group, - icount_bench_fmodf128_group, - icount_bench_fmodf16_group, - icount_bench_fmodf_group, - icount_bench_frexp_group, - icount_bench_frexpf128_group, - icount_bench_frexpf16_group, - icount_bench_frexpf_group, - icount_bench_ftoi_f128_i128_group, - icount_bench_ftoi_f128_i32_group, - icount_bench_ftoi_f128_i64_group, - icount_bench_ftoi_f128_u128_group, - icount_bench_ftoi_f128_u32_group, - icount_bench_ftoi_f128_u64_group, - icount_bench_ftoi_f32_i128_group, - icount_bench_ftoi_f32_i32_group, - icount_bench_ftoi_f32_i64_group, - icount_bench_ftoi_f32_u128_group, - icount_bench_ftoi_f32_u32_group, - icount_bench_ftoi_f32_u64_group, - icount_bench_ftoi_f64_i128_group, - icount_bench_ftoi_f64_i32_group, - icount_bench_ftoi_f64_i64_group, - icount_bench_ftoi_f64_u128_group, - icount_bench_ftoi_f64_u32_group, - icount_bench_ftoi_f64_u64_group, - icount_bench_gef128_group, - icount_bench_gef128_group, - icount_bench_gef16_group, - icount_bench_gef32_group, - icount_bench_gef64_group, - icount_bench_gtf128_group, - icount_bench_gtf16_group, - icount_bench_gtf32_group, - icount_bench_gtf64_group, - icount_bench_hypot_group, - icount_bench_hypotf_group, - icount_bench_iadd_i128_group, - icount_bench_iadd_u128_group, - icount_bench_iaddo_i128_group, - icount_bench_iaddo_u128_group, - icount_bench_idiv_i128_group, - icount_bench_idiv_i32_group, - icount_bench_idiv_i64_group, - icount_bench_idiv_u128_group, - icount_bench_idiv_u32_group, - icount_bench_idiv_u64_group, - icount_bench_idivmod_i128_group, - icount_bench_idivmod_i32_group, - icount_bench_idivmod_i64_group, - icount_bench_idivmod_u128_group, - icount_bench_idivmod_u32_group, - icount_bench_idivmod_u64_group, - icount_bench_ilogb_group, - icount_bench_ilogbf128_group, - icount_bench_ilogbf16_group, - icount_bench_ilogbf_group, - icount_bench_imod_i128_group, - icount_bench_imod_i32_group, - icount_bench_imod_i64_group, - icount_bench_imod_u128_group, - icount_bench_imod_u32_group, - icount_bench_imod_u64_group, - icount_bench_imul_i128_group, - icount_bench_imul_u64_group, - icount_bench_imulo_i128_group, - icount_bench_imulo_i32_group, - icount_bench_imulo_i64_group, - icount_bench_imulo_u128_group, - icount_bench_isub_i128_group, - icount_bench_isub_u128_group, - icount_bench_isubo_i128_group, - icount_bench_isubo_u128_group, - icount_bench_itof_i128_f128_group, - icount_bench_itof_i128_f32_group, - icount_bench_itof_i128_f64_group, - icount_bench_itof_i32_f128_group, - icount_bench_itof_i32_f32_group, - icount_bench_itof_i32_f64_group, - icount_bench_itof_i64_f128_group, - icount_bench_itof_i64_f32_group, - icount_bench_itof_i64_f64_group, - icount_bench_itof_u128_f128_group, - icount_bench_itof_u128_f32_group, - icount_bench_itof_u128_f64_group, - icount_bench_itof_u32_f128_group, - icount_bench_itof_u32_f32_group, - icount_bench_itof_u32_f64_group, - icount_bench_itof_u64_f128_group, - icount_bench_itof_u64_f32_group, - icount_bench_itof_u64_f64_group, - icount_bench_j0_group, - icount_bench_j0f_group, - icount_bench_j1_group, - icount_bench_j1f_group, - icount_bench_jn_group, - icount_bench_jnf_group, - icount_bench_ldexp_group, - icount_bench_ldexpf128_group, - icount_bench_ldexpf16_group, - icount_bench_ldexpf_group, - icount_bench_leading_zeros_u128_group, - icount_bench_leading_zeros_u32_group, - icount_bench_leading_zeros_u64_group, - icount_bench_lef128_group, - icount_bench_lef16_group, - icount_bench_lef32_group, - icount_bench_lef64_group, - icount_bench_lgamma_group, - icount_bench_lgamma_r_group, - icount_bench_lgammaf_group, - icount_bench_lgammaf_r_group, - icount_bench_log10_group, - icount_bench_log10f_group, - icount_bench_log1p_group, - icount_bench_log1pf_group, - icount_bench_log2_group, - icount_bench_log2f_group, - icount_bench_log_group, - icount_bench_logf_group, - icount_bench_lshr_u128_group, - icount_bench_lshr_u32_group, - icount_bench_lshr_u64_group, - icount_bench_ltf128_group, - icount_bench_ltf16_group, - icount_bench_ltf32_group, - icount_bench_ltf64_group, - icount_bench_modf_group, - icount_bench_modff_group, - icount_bench_mulf128_group, - icount_bench_mulf16_group, - icount_bench_mulf32_group, - icount_bench_mulf64_group, - icount_bench_narrow_f128_f16_group, - icount_bench_narrow_f128_f32_group, - icount_bench_narrow_f128_f64_group, - icount_bench_narrow_f32_f16_group, - icount_bench_narrow_f64_f16_group, - icount_bench_narrow_f64_f32_group, - icount_bench_nef128_group, - icount_bench_nef16_group, - icount_bench_nef32_group, - icount_bench_nef64_group, - icount_bench_nextafter_group, - icount_bench_nextafterf_group, - icount_bench_pow_group, - icount_bench_powf_group, - icount_bench_powif128_group, - icount_bench_powif32_group, - icount_bench_powif64_group, - icount_bench_remainder_group, - icount_bench_remainderf_group, - icount_bench_remquo_group, - icount_bench_remquof_group, - icount_bench_rint_group, - icount_bench_rintf128_group, - icount_bench_rintf16_group, - icount_bench_rintf_group, - icount_bench_round_group, - icount_bench_roundeven_group, - icount_bench_roundevenf128_group, - icount_bench_roundevenf16_group, - icount_bench_roundevenf_group, - icount_bench_roundf128_group, - icount_bench_roundf16_group, - icount_bench_roundf_group, - icount_bench_scalbn_group, - icount_bench_scalbnf128_group, - icount_bench_scalbnf16_group, - icount_bench_scalbnf_group, - icount_bench_sin_group, - icount_bench_sincos_group, - icount_bench_sincosf_group, - icount_bench_sinf_group, - icount_bench_sinh_group, - icount_bench_sinhf_group, - icount_bench_sqrt_group, - icount_bench_sqrtf128_group, - icount_bench_sqrtf16_group, - icount_bench_sqrtf_group, - icount_bench_subf128_group, - icount_bench_subf16_group, - icount_bench_subf32_group, - icount_bench_subf64_group, - icount_bench_tan_group, - icount_bench_tanf_group, - icount_bench_tanh_group, - icount_bench_tanhf_group, - icount_bench_tgamma_group, - icount_bench_tgammaf_group, - icount_bench_trailing_zeros_u128_group, - icount_bench_trailing_zeros_u32_group, - icount_bench_trailing_zeros_u64_group, - icount_bench_trunc_group, - icount_bench_truncf128_group, - icount_bench_truncf16_group, - icount_bench_truncf_group, - icount_bench_unordf128_group, - icount_bench_unordf16_group, - icount_bench_unordf32_group, - icount_bench_unordf64_group, - icount_bench_y0_group, - icount_bench_y0f_group, - icount_bench_y1_group, - icount_bench_y1f_group, - icount_bench_yn_group, - icount_bench_ynf_group, - // verify-sorted-end - // verify-apilist-end + library_benchmark_groups = [ + // Benchmarks not related to public libm math + icount_bench_u128_group, + icount_bench_hf_parse_group, + icount_bench_hf_print_group, + // verify-apilist-start + // verify-sorted-start + icount_bench_acos_group, + icount_bench_acosf_group, + icount_bench_acosh_group, + icount_bench_acoshf_group, + icount_bench_addf128_group, + icount_bench_addf16_group, + icount_bench_addf32_group, + icount_bench_addf64_group, + icount_bench_ashl_u128_group, + icount_bench_ashl_u32_group, + icount_bench_ashl_u64_group, + icount_bench_ashr_i128_group, + icount_bench_ashr_i32_group, + icount_bench_ashr_i64_group, + icount_bench_asin_group, + icount_bench_asinf_group, + icount_bench_asinh_group, + icount_bench_asinhf_group, + icount_bench_atan2_group, + icount_bench_atan2f_group, + icount_bench_atan_group, + icount_bench_atanf_group, + icount_bench_atanh_group, + icount_bench_atanhf_group, + icount_bench_cbrt_group, + icount_bench_cbrtf_group, + icount_bench_ceil_group, + icount_bench_ceilf128_group, + icount_bench_ceilf16_group, + icount_bench_ceilf_group, + icount_bench_copysign_group, + icount_bench_copysignf128_group, + icount_bench_copysignf16_group, + icount_bench_copysignf_group, + icount_bench_cos_group, + icount_bench_cosf_group, + icount_bench_cosh_group, + icount_bench_coshf_group, + icount_bench_divf128_group, + icount_bench_divf32_group, + icount_bench_divf64_group, + icount_bench_eqf128_group, + icount_bench_eqf16_group, + icount_bench_eqf32_group, + icount_bench_eqf64_group, + icount_bench_erf_group, + icount_bench_erfc_group, + icount_bench_erfcf_group, + icount_bench_erff_group, + icount_bench_exp10_group, + icount_bench_exp10f_group, + icount_bench_exp2_group, + icount_bench_exp2f_group, + icount_bench_exp_group, + icount_bench_expf_group, + icount_bench_expm1_group, + icount_bench_expm1f_group, + icount_bench_extend_f16_f128_group, + icount_bench_extend_f16_f32_group, + icount_bench_extend_f16_f64_group, + icount_bench_extend_f32_f128_group, + icount_bench_extend_f32_f64_group, + icount_bench_extend_f64_f128_group, + icount_bench_fabs_group, + icount_bench_fabsf128_group, + icount_bench_fabsf16_group, + icount_bench_fabsf_group, + icount_bench_fdim_group, + icount_bench_fdimf128_group, + icount_bench_fdimf16_group, + icount_bench_fdimf_group, + icount_bench_floor_group, + icount_bench_floorf128_group, + icount_bench_floorf16_group, + icount_bench_floorf_group, + icount_bench_fma_group, + icount_bench_fmaf128_group, + icount_bench_fmaf_group, + icount_bench_fmax_group, + icount_bench_fmaxf128_group, + icount_bench_fmaxf16_group, + icount_bench_fmaxf_group, + icount_bench_fmaximum_group, + icount_bench_fmaximum_num_group, + icount_bench_fmaximum_numf128_group, + icount_bench_fmaximum_numf16_group, + icount_bench_fmaximum_numf_group, + icount_bench_fmaximumf128_group, + icount_bench_fmaximumf16_group, + icount_bench_fmaximumf_group, + icount_bench_fmin_group, + icount_bench_fminf128_group, + icount_bench_fminf16_group, + icount_bench_fminf_group, + icount_bench_fminimum_group, + icount_bench_fminimum_num_group, + icount_bench_fminimum_numf128_group, + icount_bench_fminimum_numf16_group, + icount_bench_fminimum_numf_group, + icount_bench_fminimumf128_group, + icount_bench_fminimumf16_group, + icount_bench_fminimumf_group, + icount_bench_fmod_group, + icount_bench_fmodf128_group, + icount_bench_fmodf16_group, + icount_bench_fmodf_group, + icount_bench_frexp_group, + icount_bench_frexpf128_group, + icount_bench_frexpf16_group, + icount_bench_frexpf_group, + icount_bench_ftoi_f128_i128_group, + icount_bench_ftoi_f128_i32_group, + icount_bench_ftoi_f128_i64_group, + icount_bench_ftoi_f128_u128_group, + icount_bench_ftoi_f128_u32_group, + icount_bench_ftoi_f128_u64_group, + icount_bench_ftoi_f32_i128_group, + icount_bench_ftoi_f32_i32_group, + icount_bench_ftoi_f32_i64_group, + icount_bench_ftoi_f32_u128_group, + icount_bench_ftoi_f32_u32_group, + icount_bench_ftoi_f32_u64_group, + icount_bench_ftoi_f64_i128_group, + icount_bench_ftoi_f64_i32_group, + icount_bench_ftoi_f64_i64_group, + icount_bench_ftoi_f64_u128_group, + icount_bench_ftoi_f64_u32_group, + icount_bench_ftoi_f64_u64_group, + icount_bench_gef128_group, + icount_bench_gef128_group, + icount_bench_gef16_group, + icount_bench_gef32_group, + icount_bench_gef64_group, + icount_bench_gtf128_group, + icount_bench_gtf16_group, + icount_bench_gtf32_group, + icount_bench_gtf64_group, + icount_bench_hypot_group, + icount_bench_hypotf_group, + icount_bench_iadd_i128_group, + icount_bench_iadd_u128_group, + icount_bench_iaddo_i128_group, + icount_bench_iaddo_u128_group, + icount_bench_idiv_i128_group, + icount_bench_idiv_i32_group, + icount_bench_idiv_i64_group, + icount_bench_idiv_u128_group, + icount_bench_idiv_u32_group, + icount_bench_idiv_u64_group, + icount_bench_idivmod_i128_group, + icount_bench_idivmod_i32_group, + icount_bench_idivmod_i64_group, + icount_bench_idivmod_u128_group, + icount_bench_idivmod_u32_group, + icount_bench_idivmod_u64_group, + icount_bench_ilogb_group, + icount_bench_ilogbf128_group, + icount_bench_ilogbf16_group, + icount_bench_ilogbf_group, + icount_bench_imod_i128_group, + icount_bench_imod_i32_group, + icount_bench_imod_i64_group, + icount_bench_imod_u128_group, + icount_bench_imod_u32_group, + icount_bench_imod_u64_group, + icount_bench_imul_i128_group, + icount_bench_imul_u64_group, + icount_bench_imulo_i128_group, + icount_bench_imulo_i32_group, + icount_bench_imulo_i64_group, + icount_bench_imulo_u128_group, + icount_bench_isub_i128_group, + icount_bench_isub_u128_group, + icount_bench_isubo_i128_group, + icount_bench_isubo_u128_group, + icount_bench_itof_i128_f128_group, + icount_bench_itof_i128_f32_group, + icount_bench_itof_i128_f64_group, + icount_bench_itof_i32_f128_group, + icount_bench_itof_i32_f32_group, + icount_bench_itof_i32_f64_group, + icount_bench_itof_i64_f128_group, + icount_bench_itof_i64_f32_group, + icount_bench_itof_i64_f64_group, + icount_bench_itof_u128_f128_group, + icount_bench_itof_u128_f32_group, + icount_bench_itof_u128_f64_group, + icount_bench_itof_u32_f128_group, + icount_bench_itof_u32_f32_group, + icount_bench_itof_u32_f64_group, + icount_bench_itof_u64_f128_group, + icount_bench_itof_u64_f32_group, + icount_bench_itof_u64_f64_group, + icount_bench_j0_group, + icount_bench_j0f_group, + icount_bench_j1_group, + icount_bench_j1f_group, + icount_bench_jn_group, + icount_bench_jnf_group, + icount_bench_ldexp_group, + icount_bench_ldexpf128_group, + icount_bench_ldexpf16_group, + icount_bench_ldexpf_group, + icount_bench_leading_zeros_u128_group, + icount_bench_leading_zeros_u32_group, + icount_bench_leading_zeros_u64_group, + icount_bench_lef128_group, + icount_bench_lef16_group, + icount_bench_lef32_group, + icount_bench_lef64_group, + icount_bench_lgamma_group, + icount_bench_lgamma_r_group, + icount_bench_lgammaf_group, + icount_bench_lgammaf_r_group, + icount_bench_log10_group, + icount_bench_log10f_group, + icount_bench_log1p_group, + icount_bench_log1pf_group, + icount_bench_log2_group, + icount_bench_log2f_group, + icount_bench_log_group, + icount_bench_logf_group, + icount_bench_lshr_u128_group, + icount_bench_lshr_u32_group, + icount_bench_lshr_u64_group, + icount_bench_ltf128_group, + icount_bench_ltf16_group, + icount_bench_ltf32_group, + icount_bench_ltf64_group, + icount_bench_modf_group, + icount_bench_modff_group, + icount_bench_mulf128_group, + icount_bench_mulf16_group, + icount_bench_mulf32_group, + icount_bench_mulf64_group, + icount_bench_narrow_f128_f16_group, + icount_bench_narrow_f128_f32_group, + icount_bench_narrow_f128_f64_group, + icount_bench_narrow_f32_f16_group, + icount_bench_narrow_f64_f16_group, + icount_bench_narrow_f64_f32_group, + icount_bench_nef128_group, + icount_bench_nef16_group, + icount_bench_nef32_group, + icount_bench_nef64_group, + icount_bench_nextafter_group, + icount_bench_nextafterf_group, + icount_bench_pow_group, + icount_bench_powf_group, + icount_bench_powif128_group, + icount_bench_powif32_group, + icount_bench_powif64_group, + icount_bench_remainder_group, + icount_bench_remainderf_group, + icount_bench_remquo_group, + icount_bench_remquof_group, + icount_bench_rint_group, + icount_bench_rintf128_group, + icount_bench_rintf16_group, + icount_bench_rintf_group, + icount_bench_round_group, + icount_bench_roundeven_group, + icount_bench_roundevenf128_group, + icount_bench_roundevenf16_group, + icount_bench_roundevenf_group, + icount_bench_roundf128_group, + icount_bench_roundf16_group, + icount_bench_roundf_group, + icount_bench_scalbn_group, + icount_bench_scalbnf128_group, + icount_bench_scalbnf16_group, + icount_bench_scalbnf_group, + icount_bench_sin_group, + icount_bench_sincos_group, + icount_bench_sincosf_group, + icount_bench_sinf_group, + icount_bench_sinh_group, + icount_bench_sinhf_group, + icount_bench_sqrt_group, + icount_bench_sqrtf128_group, + icount_bench_sqrtf16_group, + icount_bench_sqrtf_group, + icount_bench_subf128_group, + icount_bench_subf16_group, + icount_bench_subf32_group, + icount_bench_subf64_group, + icount_bench_tan_group, + icount_bench_tanf_group, + icount_bench_tanh_group, + icount_bench_tanhf_group, + icount_bench_tgamma_group, + icount_bench_tgammaf_group, + icount_bench_trailing_zeros_u128_group, + icount_bench_trailing_zeros_u32_group, + icount_bench_trailing_zeros_u64_group, + icount_bench_trunc_group, + icount_bench_truncf128_group, + icount_bench_truncf16_group, + icount_bench_truncf_group, + icount_bench_unordf128_group, + icount_bench_unordf16_group, + icount_bench_unordf32_group, + icount_bench_unordf64_group, + icount_bench_y0_group, + icount_bench_y0f_group, + icount_bench_y1_group, + icount_bench_y1f_group, + icount_bench_yn_group, + icount_bench_ynf_group, + // verify-sorted-end + // verify-apilist-end + ] ); From b6d05f59939b1eca518e176f27f76b5164be5e73 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Fri, 27 Mar 2026 04:01:27 -0500 Subject: [PATCH 036/183] test: Move `libm-macros/shared.rs` to a new `api-list-common` crate This file is already used in two places and was going to be needed in another. Turning it into its own crate makes things easier to work with, and allows for the removal of a few `allow(dead_code)` instances. --- library/compiler-builtins/Cargo.lock | 6 ++ library/compiler-builtins/Cargo.toml | 3 + .../crates/api-list-common/Cargo.toml | 6 ++ .../shared.rs => api-list-common/src/lib.rs} | 6 +- .../crates/libm-macros/Cargo.toml | 1 + .../crates/libm-macros/src/lib.rs | 58 +++++++++---------- .../compiler-builtins/libm-test/Cargo.toml | 1 + library/compiler-builtins/libm-test/src/op.rs | 6 +- 8 files changed, 45 insertions(+), 42 deletions(-) create mode 100644 library/compiler-builtins/crates/api-list-common/Cargo.toml rename library/compiler-builtins/crates/{libm-macros/src/shared.rs => api-list-common/src/lib.rs} (99%) diff --git a/library/compiler-builtins/Cargo.lock b/library/compiler-builtins/Cargo.lock index 220e7048512b5..274084fb4d64f 100644 --- a/library/compiler-builtins/Cargo.lock +++ b/library/compiler-builtins/Cargo.lock @@ -88,6 +88,10 @@ version = "1.0.101" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5f0e0fee31ef5ed1ba1316088939cea399010ed7731dba877ed44aeb407a75ea" +[[package]] +name = "api-list-common" +version = "0.1.0" + [[package]] name = "assert_cmd" version = "2.1.2" @@ -653,6 +657,7 @@ checksum = "b6d2cec3eae94f9f509c767b45932f1ada8350c4bdb85af2fcab4a3c14807981" name = "libm-macros" version = "0.1.0" dependencies = [ + "api-list-common", "heck", "proc-macro2", "quote", @@ -664,6 +669,7 @@ name = "libm-test" version = "0.1.0" dependencies = [ "anyhow", + "api-list-common", "compiler_builtins", "criterion", "getrandom", diff --git a/library/compiler-builtins/Cargo.toml b/library/compiler-builtins/Cargo.toml index 26a056f434967..8845f580f8846 100644 --- a/library/compiler-builtins/Cargo.toml +++ b/library/compiler-builtins/Cargo.toml @@ -3,6 +3,7 @@ resolver = "2" members = [ "builtins-shim", "builtins-test", + "crates/api-list-common", "crates/libm-macros", "crates/musl-math-sys", "crates/panic-handler", @@ -15,6 +16,7 @@ members = [ default-members = [ "builtins-shim", "builtins-test", + "crates/api-list-common", "crates/libm-macros", "libm", "libm-test", @@ -33,6 +35,7 @@ exclude = [ [workspace.dependencies] anyhow = "1.0.101" +api-list-common = { path = "crates/api-list-common" } assert_cmd = "2.1.2" cc = "1.2.56" cfg-if = "1.0.4" diff --git a/library/compiler-builtins/crates/api-list-common/Cargo.toml b/library/compiler-builtins/crates/api-list-common/Cargo.toml new file mode 100644 index 0000000000000..bf9262eb828ff --- /dev/null +++ b/library/compiler-builtins/crates/api-list-common/Cargo.toml @@ -0,0 +1,6 @@ +[package] +name = "api-list-common" +version = "0.1.0" +edition = "2024" +publish = false +license = "MIT OR Apache-2.0" diff --git a/library/compiler-builtins/crates/libm-macros/src/shared.rs b/library/compiler-builtins/crates/api-list-common/src/lib.rs similarity index 99% rename from library/compiler-builtins/crates/libm-macros/src/shared.rs rename to library/compiler-builtins/crates/api-list-common/src/lib.rs index 9a22d199536c0..2fe3d5f44805d 100644 --- a/library/compiler-builtins/crates/libm-macros/src/shared.rs +++ b/library/compiler-builtins/crates/api-list-common/src/lib.rs @@ -1,4 +1,4 @@ -/* List of all functions that is shared between `libm-macros` and `libm-test`. */ +//! A list of API we have available, shared among various test crates. use std::collections::HashSet; use std::fmt; @@ -18,7 +18,6 @@ pub enum OpScope { /// Part of `libm`'s public API. LibmPublic, /// Functions internal to `libm`, e.g. `rem_pio2`. - #[allow(dead_code)] LibmPrivate, /// Functions part of the public API for `compiler-builtins`. BuiltinsPublic, @@ -1346,7 +1345,6 @@ const ALL_OPERATIONS_NESTED: &[NestedOp] = &[ ]; /// A type used in a function signature. -#[allow(dead_code)] #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] pub enum Ty { F16, @@ -1373,7 +1371,6 @@ pub enum Ty { impl Ty { /// The number of bits needed to represent this type's possible values. That is, /// `log2(variant_count)`. - #[allow(dead_code)] pub fn effective_bits(self) -> u32 { match self { Ty::Bool => 1, @@ -1434,7 +1431,6 @@ impl Ty { } /// How a function should get grouped for things like extensive tests. -#[allow(dead_code)] #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] pub enum Group { F16, diff --git a/library/compiler-builtins/crates/libm-macros/Cargo.toml b/library/compiler-builtins/crates/libm-macros/Cargo.toml index f99a92e21c709..920cc32104943 100644 --- a/library/compiler-builtins/crates/libm-macros/Cargo.toml +++ b/library/compiler-builtins/crates/libm-macros/Cargo.toml @@ -9,6 +9,7 @@ license = "MIT OR Apache-2.0" proc-macro = true [dependencies] +api-list-common.workspace = true heck.workspace = true proc-macro2.workspace = true quote.workspace = true diff --git a/library/compiler-builtins/crates/libm-macros/src/lib.rs b/library/compiler-builtins/crates/libm-macros/src/lib.rs index 09369e8de3a93..7bafd0ce8e1d4 100644 --- a/library/compiler-builtins/crates/libm-macros/src/lib.rs +++ b/library/compiler-builtins/crates/libm-macros/src/lib.rs @@ -1,13 +1,11 @@ mod enums; mod parse; -mod shared; +use api_list_common::{ALL_OPERATIONS, Group, MathOpInfo, Ty}; use parse::{Invocation, StructuredInput}; use proc_macro as pm; use proc_macro2::{self as pm2, Span}; use quote::{ToTokens, quote}; -use shared::Group; -pub(crate) use shared::{ALL_OPERATIONS, MathOpInfo, Ty}; use syn::spanned::Spanned; use syn::visit_mut::VisitMut; use syn::{Ident, ItemEnum, PathArguments, PathSegment}; @@ -383,10 +381,6 @@ fn expand(input: StructuredInput, fn_list: &[&MathOpInfo]) -> syn::Result pm2::TokenStream::new(), }; - let c_args = &func.c_sig.args; - let c_ret = &func.c_sig.returns; - let rust_args = &func.rust_sig.args; - let rust_ret = &func.rust_sig.returns; let path = syn::Path { leading_colon: None, segments: func @@ -401,6 +395,10 @@ fn expand(input: StructuredInput, fn_list: &[&MathOpInfo]) -> syn::Result quote! { CFn: fn( #(#c_args),* ,) -> ( #(#c_ret),* ), }, "CArgs" => quote! { CArgs: ( #(#c_args),* ,), }, @@ -522,30 +520,26 @@ fn base_name(name: &str) -> &str { ret } -impl ToTokens for Ty { - fn to_tokens(&self, tokens: &mut pm2::TokenStream) { - let ts = match self { - Ty::F16 => quote! { f16 }, - Ty::F32 => quote! { f32 }, - Ty::F64 => quote! { f64 }, - Ty::F128 => quote! { f128 }, - Ty::I32 => quote! { i32 }, - Ty::I64 => quote! { i64 }, - Ty::I128 => quote! { i128 }, - Ty::U32 => quote! { u32 }, - Ty::U64 => quote! { u64 }, - Ty::U128 => quote! { u128 }, - Ty::USize => quote! { usize }, - Ty::Bool => quote! { bool }, - Ty::CInt => quote! { ::core::ffi::c_int }, - Ty::MutF16 => quote! { &'a mut f16 }, - Ty::MutF32 => quote! { &'a mut f32 }, - Ty::MutF64 => quote! { &'a mut f64 }, - Ty::MutF128 => quote! { &'a mut f128 }, - Ty::MutI32 => quote! { &'a mut i32 }, - Ty::MutCInt => quote! { &'a mut core::ffi::c_int }, - }; - - tokens.extend(ts); +fn ty_to_tokens(ty: Ty) -> pm2::TokenStream { + match ty { + Ty::F16 => quote! { f16 }, + Ty::F32 => quote! { f32 }, + Ty::F64 => quote! { f64 }, + Ty::F128 => quote! { f128 }, + Ty::I32 => quote! { i32 }, + Ty::I64 => quote! { i64 }, + Ty::I128 => quote! { i128 }, + Ty::U32 => quote! { u32 }, + Ty::U64 => quote! { u64 }, + Ty::U128 => quote! { u128 }, + Ty::USize => quote! { usize }, + Ty::Bool => quote! { bool }, + Ty::CInt => quote! { ::core::ffi::c_int }, + Ty::MutF16 => quote! { &'a mut f16 }, + Ty::MutF32 => quote! { &'a mut f32 }, + Ty::MutF64 => quote! { &'a mut f64 }, + Ty::MutF128 => quote! { &'a mut f128 }, + Ty::MutI32 => quote! { &'a mut i32 }, + Ty::MutCInt => quote! { &'a mut core::ffi::c_int }, } } diff --git a/library/compiler-builtins/libm-test/Cargo.toml b/library/compiler-builtins/libm-test/Cargo.toml index c2d1b9f9ccbd5..abc9bc6f75e11 100644 --- a/library/compiler-builtins/libm-test/Cargo.toml +++ b/library/compiler-builtins/libm-test/Cargo.toml @@ -7,6 +7,7 @@ license = "MIT OR Apache-2.0" [dependencies] anyhow.workspace = true +api-list-common.workspace = true compiler_builtins = { workspace = true, default-features = false, features = ["unstable-public-internals"] } # This is not directly used but is required so we can enable `gmp-mpfr-sys/force-cross`. gmp-mpfr-sys = { workspace = true, optional = true } diff --git a/library/compiler-builtins/libm-test/src/op.rs b/library/compiler-builtins/libm-test/src/op.rs index 14ee67b8d83cc..809d518755262 100644 --- a/library/compiler-builtins/libm-test/src/op.rs +++ b/library/compiler-builtins/libm-test/src/op.rs @@ -16,14 +16,10 @@ use std::fmt; use std::panic::{RefUnwindSafe, UnwindSafe}; -pub use shared::{ALL_OPERATIONS, Group, MathOpInfo, Ty}; +pub use api_list_common::{ALL_OPERATIONS, Group, MathOpInfo, Ty}; use crate::{CheckOutput, Tuple, TupleCall}; -mod shared { - include!("../../crates/libm-macros/src/shared.rs"); -} - /// An enum representing each possible symbol name (`sin`, `sinf`, `sinl`, etc). #[libm_macros::function_enum(BaseName)] #[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] From 7332ac06c067f8dfa70623c6cb5004a0cd69ad79 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Fri, 27 Mar 2026 04:06:36 -0500 Subject: [PATCH 037/183] api-list: Move sort and unique checks to tests Having them as part of the `LazyLock` means that if something is unsorted, the macro panics and produces a lot of warnings. Move these to a test instead. --- .../crates/api-list-common/src/lib.rs | 48 ++++++++++++------- 1 file changed, 32 insertions(+), 16 deletions(-) diff --git a/library/compiler-builtins/crates/api-list-common/src/lib.rs b/library/compiler-builtins/crates/api-list-common/src/lib.rs index 2fe3d5f44805d..3e5868e752bcb 100644 --- a/library/compiler-builtins/crates/api-list-common/src/lib.rs +++ b/library/compiler-builtins/crates/api-list-common/src/lib.rs @@ -1,6 +1,5 @@ //! A list of API we have available, shared among various test crates. -use std::collections::HashSet; use std::fmt; use std::sync::LazyLock; @@ -1518,24 +1517,41 @@ pub static ALL_OPERATIONS: LazyLock> = LazyLock::new(|| { }; ret.push(api); } - - if !fn_names.is_sorted() { - let mut sorted = (*fn_names).to_owned(); - sorted.sort_unstable(); - panic!("names list is not sorted: {fn_names:?}\nExpected: {sorted:?}"); - } } ret.sort_by_key(|item| item.name); + ret +}); + +#[cfg(test)] +mod tests { + use std::collections::HashSet; + + pub use super::*; - let mut names = HashSet::new(); - let mut paths = HashSet::new(); - for item in &ret { - let new_name = names.insert(item.name); - assert!(new_name, "duplicate name `{item:?}`"); - let new_path = paths.insert(&item.path); - assert!(new_path, "duplicate path`{item:?}`"); + #[test] + fn sorted_fn_list() { + for op in ALL_OPERATIONS_NESTED { + if !op.fn_list.is_sorted() { + let mut sorted = (*op.fn_list).to_owned(); + sorted.sort_unstable(); + panic!( + "names list is not sorted: {:?}\nExpected: {sorted:?}", + op.fn_list + ); + } + } } - ret -}); + #[test] + fn no_duplicates_in_list() { + let mut names = HashSet::new(); + let mut paths = HashSet::new(); + for item in &*ALL_OPERATIONS { + let new_name = names.insert(item.name); + assert!(new_name, "duplicate name `{item:?}`"); + let new_path = paths.insert(&item.path); + assert!(new_path, "duplicate path`{item:?}`"); + } + } +} From d7f6c3d777f76577391eb07725912c858c59e954 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Fri, 27 Mar 2026 16:27:58 -0500 Subject: [PATCH 038/183] ci: Add a retry to the `compiler-rt` download --- library/compiler-builtins/ci/download-compiler-rt.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/ci/download-compiler-rt.sh b/library/compiler-builtins/ci/download-compiler-rt.sh index bf7f8c2489643..87b337d8255bb 100755 --- a/library/compiler-builtins/ci/download-compiler-rt.sh +++ b/library/compiler-builtins/ci/download-compiler-rt.sh @@ -6,5 +6,5 @@ set -eux rust_llvm_version=20.1-2025-02-13 -curl -L -o code.tar.gz "https://github.com/rust-lang/llvm-project/archive/rustc/${rust_llvm_version}.tar.gz" +curl -L --retry 3 -o code.tar.gz "https://github.com/rust-lang/llvm-project/archive/rustc/${rust_llvm_version}.tar.gz" tar xzf code.tar.gz --strip-components 1 llvm-project-rustc-${rust_llvm_version}/compiler-rt From d7f20a92676ada4d234e38b850d0d5ac151206ed Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Fri, 27 Mar 2026 17:39:16 -0500 Subject: [PATCH 039/183] ci: Add benchmarks for i686 This is one arch that is reasonably easy to set up without native runners, and gives us an idea of how the crates do on 32-bit platforms. --- .../.github/workflows/main.yaml | 8 +++++--- library/compiler-builtins/ci/bench-icount.sh | 1 + .../compiler-builtins/ci/install-bench-deps.sh | 16 ++++++++++++++-- 3 files changed, 20 insertions(+), 5 deletions(-) diff --git a/library/compiler-builtins/.github/workflows/main.yaml b/library/compiler-builtins/.github/workflows/main.yaml index 1f16ab9a355e9..1fe91a810e8a5 100644 --- a/library/compiler-builtins/.github/workflows/main.yaml +++ b/library/compiler-builtins/.github/workflows/main.yaml @@ -283,10 +283,12 @@ jobs: fail-fast: false matrix: include: - - target: x86_64-unknown-linux-gnu - os: ubuntu-24.04 - target: aarch64-unknown-linux-gnu os: ubuntu-24.04-arm + - target: i686-unknown-linux-gnu + os: ubuntu-24.04 + - target: x86_64-unknown-linux-gnu + os: ubuntu-24.04 runs-on: ${{ matrix.os }} env: JOB_TARGET: ${{ matrix.target }} @@ -298,7 +300,7 @@ jobs: tool: cargo-binstall@1.17.7 - name: Set up dependencies - run: ./ci/install-bench-deps.sh + run: ./ci/install-bench-deps.sh "$JOB_TARGET" - uses: Swatinem/rust-cache@e18b497796c12c097a38f9edb9d0641fb99eee32 # v2 with: key: ${{ matrix.target }} diff --git a/library/compiler-builtins/ci/bench-icount.sh b/library/compiler-builtins/ci/bench-icount.sh index 6d92b50a6dae7..c7f25dfa18ef6 100755 --- a/library/compiler-builtins/ci/bench-icount.sh +++ b/library/compiler-builtins/ci/bench-icount.sh @@ -29,6 +29,7 @@ tag="$(echo "$target" | cut -d'-' -f1)" # Run benchmarks once function run_icount_benchmarks() { cargo_args=( + "--target" "$target" "--bench" "*icount*" "--no-default-features" "--features" "unstable,unstable-float,icount" diff --git a/library/compiler-builtins/ci/install-bench-deps.sh b/library/compiler-builtins/ci/install-bench-deps.sh index 61f4723c0358d..7d73ed0d32f55 100755 --- a/library/compiler-builtins/ci/install-bench-deps.sh +++ b/library/compiler-builtins/ci/install-bench-deps.sh @@ -1,10 +1,22 @@ -#!/bin/sh +#!/bin/bash # Install needed dependencies for gungraun. +set -eux + +target="${1:-}" + +# Needed for gungraun +deps=(valgrind gdb libc6-dbg) + +[[ "$target" = *"i686"* ]] && deps+=(gcc-multilib) + sudo apt-get update -sudo apt-get install -y valgrind gdb libc6-dbg # Needed for gungraun +sudo apt-get install -y "${deps[@]}" + rustup update "$BENCHMARK_RUSTC" --no-self-update rustup default "$BENCHMARK_RUSTC" +[ -n "$target" ] && rustup target add "$target" + # Install the version of gungraun-runner that is specified in Cargo.toml gungraun_version="$(cargo metadata --format-version=1 --features icount | jq -r '.packages[] | select(.name == "gungraun").version')" From 6dc3b2680c7ad0121890a8d84ee37d19b319984b Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Fri, 27 Mar 2026 18:48:30 -0500 Subject: [PATCH 040/183] ci: Remove wall time benchmarks from CI The icount benchmarks are significantly more reliable, and I don't think these results get looked at too much. They can be run locally if needed, so save the CI time here. --- library/compiler-builtins/.github/workflows/main.yaml | 3 --- 1 file changed, 3 deletions(-) diff --git a/library/compiler-builtins/.github/workflows/main.yaml b/library/compiler-builtins/.github/workflows/main.yaml index 1fe91a810e8a5..57a40d4fd9b29 100644 --- a/library/compiler-builtins/.github/workflows/main.yaml +++ b/library/compiler-builtins/.github/workflows/main.yaml @@ -319,9 +319,6 @@ jobs: name: ${{ env.BASELINE_NAME }} path: ${{ env.BASELINE_NAME }}.tar.xz - - name: Run wall time benchmarks - run: ./ci/bench-walltime.sh - - name: Print test logs if available if: always() run: if [ -f "target/test-log.txt" ]; then cat target/test-log.txt; fi From 5e472e625d4e8a8a65b1b4f7b0b7e49a37671c68 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Sun, 29 Mar 2026 14:12:29 -0500 Subject: [PATCH 041/183] util: Allow a trailing comma for operands Make it easier to copy test output when evaluating multi-input functions. --- library/compiler-builtins/crates/util/src/main.rs | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/library/compiler-builtins/crates/util/src/main.rs b/library/compiler-builtins/crates/util/src/main.rs index dbeb923364db5..ac2c126d8c0d1 100644 --- a/library/compiler-builtins/crates/util/src/main.rs +++ b/library/compiler-builtins/crates/util/src/main.rs @@ -37,7 +37,14 @@ SUBCOMMAND: fn main() { let args = env::args().collect::>(); - let str_args = args.iter().map(|s| s.as_str()).collect::>(); + let str_args = args + .iter() + .map(|s| { + // Allow pasting from comma-separated arguments + let s = s.as_str(); + s.strip_suffix(",").unwrap_or(s) + }) + .collect::>(); match &str_args.as_slice()[1..] { ["eval" | "x", basis, op, inputs @ ..] => do_eval(basis, op, inputs), From bd2b448e089588bcfc0c5381ee94df86854ed4db Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Sat, 28 Mar 2026 04:33:56 -0500 Subject: [PATCH 042/183] test: Introduce a `cases!` macro for adding specific test cases --- .../libm-test/src/generate/case_list.rs | 808 +++++++++--------- 1 file changed, 388 insertions(+), 420 deletions(-) diff --git a/library/compiler-builtins/libm-test/src/generate/case_list.rs b/library/compiler-builtins/libm-test/src/generate/case_list.rs index c85608eb9900d..5be8f19e709d7 100644 --- a/library/compiler-builtins/libm-test/src/generate/case_list.rs +++ b/library/compiler-builtins/libm-test/src/generate/case_list.rs @@ -17,25 +17,36 @@ pub struct TestCase { pub output: Option, } -impl TestCase { - #[expect(dead_code)] - fn append_inputs(v: &mut Vec, l: &[Op::RustArgs]) { - v.extend(l.iter().copied().map(|input| Self { - input, +macro_rules! cases { + ( + $( + $(#[$($meta:tt)*])* + ($($tt:tt)*) + ),* $(,)? + ) => {{ + Vec::from_iter([ + $( + $(#[$($meta)*])* + cases!(@single $($tt)*), + )* + ]) + }}; + + // Variant without a result, which will check against MPFR. + (@single ($($arg:expr),* $(,)?), None $(,)?) => { + TestCase{ + input: ($($arg,)*), output: None, - })); - } + } + }; - fn append_pairs(v: &mut Vec, l: &[(Op::RustArgs, Option)]) - where - Op::RustRet: Copy, - { - v.extend( - l.iter() - .copied() - .map(|(input, output)| Self { input, output }), - ); - } + // Variant for when the result is specified. + (@single ($($arg:expr),* $(,)?), $res:expr $(,)?) => { + TestCase{ + input: ($($arg,)*), + output: Some($res), + } + }; } /******************************** @@ -44,622 +55,622 @@ impl TestCase { #[cfg(f16_enabled)] fn addf16_cases() -> Vec> { - vec![] + cases![] } fn addf32_cases() -> Vec> { - vec![] + cases![] } fn addf64_cases() -> Vec> { - vec![] + cases![] } #[cfg(f128_enabled)] fn addf128_cases() -> Vec> { - vec![] + cases![] } #[cfg(f16_enabled)] fn subf16_cases() -> Vec> { - vec![] + cases![] } fn subf32_cases() -> Vec> { - vec![] + cases![] } fn subf64_cases() -> Vec> { - vec![] + cases![] } #[cfg(f128_enabled)] fn subf128_cases() -> Vec> { - vec![] + cases![] } #[cfg(f16_enabled)] fn mulf16_cases() -> Vec> { - vec![] + cases![] } fn mulf32_cases() -> Vec> { - vec![] + cases![] } fn mulf64_cases() -> Vec> { - vec![] + cases![] } #[cfg(f128_enabled)] fn mulf128_cases() -> Vec> { - vec![] + cases![] } fn divf32_cases() -> Vec> { - vec![] + cases![] } fn divf64_cases() -> Vec> { - vec![] + cases![] } #[cfg(f128_enabled)] fn divf128_cases() -> Vec> { - vec![] + cases![] } fn powif32_cases() -> Vec> { - vec![] + cases![] } fn powif64_cases() -> Vec> { - vec![] + cases![] } #[cfg(f128_enabled)] fn powif128_cases() -> Vec> { - vec![] + cases![] } /* comparison */ #[cfg(f16_enabled)] fn eqf16_cases() -> Vec> { - vec![] + cases![] } fn eqf32_cases() -> Vec> { - vec![] + cases![] } fn eqf64_cases() -> Vec> { - vec![] + cases![] } #[cfg(f128_enabled)] fn eqf128_cases() -> Vec> { - vec![] + cases![] } #[cfg(f16_enabled)] fn gtf16_cases() -> Vec> { - vec![] + cases![] } fn gtf32_cases() -> Vec> { - vec![] + cases![] } fn gtf64_cases() -> Vec> { - vec![] + cases![] } #[cfg(f128_enabled)] fn gtf128_cases() -> Vec> { - vec![] + cases![] } #[cfg(f16_enabled)] fn gef16_cases() -> Vec> { - vec![] + cases![] } fn gef32_cases() -> Vec> { - vec![] + cases![] } fn gef64_cases() -> Vec> { - vec![] + cases![] } #[cfg(f128_enabled)] fn gef128_cases() -> Vec> { - vec![] + cases![] } #[cfg(f16_enabled)] fn ltf16_cases() -> Vec> { - vec![] + cases![] } fn ltf32_cases() -> Vec> { - vec![] + cases![] } fn ltf64_cases() -> Vec> { - vec![] + cases![] } #[cfg(f128_enabled)] fn ltf128_cases() -> Vec> { - vec![] + cases![] } #[cfg(f16_enabled)] fn lef16_cases() -> Vec> { - vec![] + cases![] } fn lef32_cases() -> Vec> { - vec![] + cases![] } fn lef64_cases() -> Vec> { - vec![] + cases![] } #[cfg(f128_enabled)] fn lef128_cases() -> Vec> { - vec![] + cases![] } #[cfg(f16_enabled)] fn nef16_cases() -> Vec> { - vec![] + cases![] } fn nef32_cases() -> Vec> { - vec![] + cases![] } fn nef64_cases() -> Vec> { - vec![] + cases![] } #[cfg(f128_enabled)] fn nef128_cases() -> Vec> { - vec![] + cases![] } #[cfg(f16_enabled)] fn unordf16_cases() -> Vec> { - vec![] + cases![] } fn unordf32_cases() -> Vec> { - vec![] + cases![] } fn unordf64_cases() -> Vec> { - vec![] + cases![] } #[cfg(f128_enabled)] fn unordf128_cases() -> Vec> { - vec![] + cases![] } /* conversion */ #[cfg(f16_enabled)] fn extend_f16_f32_cases() -> Vec> { - vec![] + cases![] } #[cfg(f16_enabled)] fn extend_f16_f64_cases() -> Vec> { - vec![] + cases![] } #[cfg(f16_enabled)] #[cfg(f128_enabled)] fn extend_f16_f128_cases() -> Vec> { - vec![] + cases![] } fn extend_f32_f64_cases() -> Vec> { - vec![] + cases![] } #[cfg(f128_enabled)] fn extend_f32_f128_cases() -> Vec> { - vec![] + cases![] } #[cfg(f128_enabled)] fn extend_f64_f128_cases() -> Vec> { - vec![] + cases![] } #[cfg(f16_enabled)] fn narrow_f32_f16_cases() -> Vec> { - vec![] + cases![] } #[cfg(f16_enabled)] fn narrow_f64_f16_cases() -> Vec> { - vec![] + cases![] } fn narrow_f64_f32_cases() -> Vec> { - vec![] + cases![] } #[cfg(f16_enabled)] #[cfg(f128_enabled)] fn narrow_f128_f16_cases() -> Vec> { - vec![] + cases![] } #[cfg(f128_enabled)] fn narrow_f128_f32_cases() -> Vec> { - vec![] + cases![] } #[cfg(f128_enabled)] fn narrow_f128_f64_cases() -> Vec> { - vec![] + cases![] } fn ftoi_f32_i32_cases() -> Vec> { - vec![] + cases![] } fn ftoi_f32_i64_cases() -> Vec> { - vec![] + cases![] } fn ftoi_f32_i128_cases() -> Vec> { - vec![] + cases![] } fn ftoi_f64_i32_cases() -> Vec> { - vec![] + cases![] } fn ftoi_f64_i64_cases() -> Vec> { - vec![] + cases![] } fn ftoi_f64_i128_cases() -> Vec> { - vec![] + cases![] } #[cfg(f128_enabled)] fn ftoi_f128_i32_cases() -> Vec> { - vec![] + cases![] } #[cfg(f128_enabled)] fn ftoi_f128_i64_cases() -> Vec> { - vec![] + cases![] } #[cfg(f128_enabled)] fn ftoi_f128_i128_cases() -> Vec> { - vec![] + cases![] } fn ftoi_f32_u32_cases() -> Vec> { - vec![] + cases![] } fn ftoi_f32_u64_cases() -> Vec> { - vec![] + cases![] } fn ftoi_f32_u128_cases() -> Vec> { - vec![] + cases![] } fn ftoi_f64_u32_cases() -> Vec> { - vec![] + cases![] } fn ftoi_f64_u64_cases() -> Vec> { - vec![] + cases![] } fn ftoi_f64_u128_cases() -> Vec> { - vec![] + cases![] } #[cfg(f128_enabled)] fn ftoi_f128_u32_cases() -> Vec> { - vec![] + cases![] } #[cfg(f128_enabled)] fn ftoi_f128_u64_cases() -> Vec> { - vec![] + cases![] } #[cfg(f128_enabled)] fn ftoi_f128_u128_cases() -> Vec> { - vec![] + cases![] } fn itof_i32_f32_cases() -> Vec> { - vec![] + cases![] } fn itof_i64_f32_cases() -> Vec> { - vec![] + cases![] } fn itof_i128_f32_cases() -> Vec> { - vec![] + cases![] } fn itof_i32_f64_cases() -> Vec> { - vec![] + cases![] } fn itof_i64_f64_cases() -> Vec> { - vec![] + cases![] } fn itof_i128_f64_cases() -> Vec> { - vec![] + cases![] } #[cfg(f128_enabled)] fn itof_i32_f128_cases() -> Vec> { - vec![] + cases![] } #[cfg(f128_enabled)] fn itof_i64_f128_cases() -> Vec> { - vec![] + cases![] } #[cfg(f128_enabled)] fn itof_i128_f128_cases() -> Vec> { - vec![] + cases![] } fn itof_u32_f32_cases() -> Vec> { - vec![] + cases![] } fn itof_u64_f32_cases() -> Vec> { - vec![] + cases![] } fn itof_u128_f32_cases() -> Vec> { - vec![] + cases![] } fn itof_u32_f64_cases() -> Vec> { - vec![] + cases![] } fn itof_u64_f64_cases() -> Vec> { - vec![] + cases![] } fn itof_u128_f64_cases() -> Vec> { - vec![] + cases![] } #[cfg(f128_enabled)] fn itof_u32_f128_cases() -> Vec> { - vec![] + cases![] } #[cfg(f128_enabled)] fn itof_u64_f128_cases() -> Vec> { - vec![] + cases![] } #[cfg(f128_enabled)] fn itof_u128_f128_cases() -> Vec> { - vec![] + cases![] } /* int arithmetic */ fn iadd_i128_cases() -> Vec> { - vec![] + cases![] } fn iadd_u128_cases() -> Vec> { - vec![] + cases![] } fn iaddo_i128_cases() -> Vec> { - vec![] + cases![] } fn iaddo_u128_cases() -> Vec> { - vec![] + cases![] } fn isub_i128_cases() -> Vec> { - vec![] + cases![] } fn isub_u128_cases() -> Vec> { - vec![] + cases![] } fn isubo_i128_cases() -> Vec> { - vec![] + cases![] } fn isubo_u128_cases() -> Vec> { - vec![] + cases![] } fn idiv_i128_cases() -> Vec> { - vec![] + cases![] } fn idiv_i32_cases() -> Vec> { - vec![] + cases![] } fn idiv_i64_cases() -> Vec> { - vec![] + cases![] } fn idiv_u128_cases() -> Vec> { - vec![] + cases![] } fn idiv_u32_cases() -> Vec> { - vec![] + cases![] } fn idiv_u64_cases() -> Vec> { - vec![] + cases![] } fn idivmod_i128_cases() -> Vec> { - vec![] + cases![] } fn idivmod_i32_cases() -> Vec> { - vec![] + cases![] } fn idivmod_i64_cases() -> Vec> { - vec![] + cases![] } fn idivmod_u128_cases() -> Vec> { - vec![] + cases![] } fn idivmod_u32_cases() -> Vec> { - vec![] + cases![] } fn idivmod_u64_cases() -> Vec> { - vec![] + cases![] } fn imod_i128_cases() -> Vec> { - vec![] + cases![] } fn imod_i32_cases() -> Vec> { - vec![] + cases![] } fn imod_i64_cases() -> Vec> { - vec![] + cases![] } fn imod_u128_cases() -> Vec> { - vec![] + cases![] } fn imod_u32_cases() -> Vec> { - vec![] + cases![] } fn imod_u64_cases() -> Vec> { - vec![] + cases![] } fn imul_i128_cases() -> Vec> { - vec![] + cases![] } fn imul_u64_cases() -> Vec> { - vec![] + cases![] } fn imulo_i128_cases() -> Vec> { - vec![] + cases![] } fn imulo_i32_cases() -> Vec> { - vec![] + cases![] } fn imulo_i64_cases() -> Vec> { - vec![] + cases![] } fn imulo_u128_cases() -> Vec> { - vec![] + cases![] } /* int shifts */ fn ashl_u32_cases() -> Vec> { - vec![] + cases![] } fn ashl_u64_cases() -> Vec> { - vec![] + cases![] } fn ashl_u128_cases() -> Vec> { - vec![] + cases![] } fn ashr_i32_cases() -> Vec> { - vec![] + cases![] } fn ashr_i64_cases() -> Vec> { - vec![] + cases![] } fn ashr_i128_cases() -> Vec> { - vec![] + cases![] } fn lshr_u32_cases() -> Vec> { - vec![] + cases![] } fn lshr_u64_cases() -> Vec> { - vec![] + cases![] } fn lshr_u128_cases() -> Vec> { - vec![] + cases![] } /* int bitwise ops */ fn leading_zeros_u32_cases() -> Vec> { - vec![] + cases![] } fn leading_zeros_u64_cases() -> Vec> { - vec![] + cases![] } fn leading_zeros_u128_cases() -> Vec> { - vec![] + cases![] } fn trailing_zeros_u32_cases() -> Vec> { - vec![] + cases![] } fn trailing_zeros_u64_cases() -> Vec> { - vec![] + cases![] } fn trailing_zeros_u128_cases() -> Vec> { - vec![] + cases![] } /******************* @@ -667,813 +678,770 @@ fn trailing_zeros_u128_cases() -> Vec *******************/ fn acos_cases() -> Vec> { - vec![] + cases![] } fn acosf_cases() -> Vec> { - vec![] + cases![] } fn acosh_cases() -> Vec> { - vec![] + cases![] } fn acoshf_cases() -> Vec> { - vec![] + cases![] } fn asin_cases() -> Vec> { - vec![] + cases![] } fn asinf_cases() -> Vec> { - vec![] + cases![] } fn asinh_cases() -> Vec> { - vec![] + cases![] } fn asinhf_cases() -> Vec> { - vec![] + cases![] } fn atan_cases() -> Vec> { - vec![] + cases![] } fn atan2_cases() -> Vec> { - vec![] + cases![] } fn atan2f_cases() -> Vec> { - vec![] + cases![] } fn atanf_cases() -> Vec> { - vec![] + cases![] } fn atanh_cases() -> Vec> { - vec![] + cases![] } fn atanhf_cases() -> Vec> { - vec![] + cases![] } fn cbrt_cases() -> Vec> { - vec![] + cases![] } fn cbrtf_cases() -> Vec> { - vec![] + cases![] } fn ceil_cases() -> Vec> { - vec![] + cases![] } fn ceilf_cases() -> Vec> { - vec![] + cases![] } #[cfg(f128_enabled)] fn ceilf128_cases() -> Vec> { - vec![] + cases![] } #[cfg(f16_enabled)] fn ceilf16_cases() -> Vec> { - vec![] + cases![] } fn copysign_cases() -> Vec> { - vec![] + cases![] } fn copysignf_cases() -> Vec> { - vec![] + cases![] } #[cfg(f128_enabled)] fn copysignf128_cases() -> Vec> { - vec![] + cases![] } #[cfg(f16_enabled)] fn copysignf16_cases() -> Vec> { - vec![] + cases![] } fn cos_cases() -> Vec> { - vec![] + cases![] } fn cosf_cases() -> Vec> { - vec![] + cases![] } fn cosh_cases() -> Vec> { - vec![] + cases![] } fn coshf_cases() -> Vec> { - vec![] + cases![] } fn erf_cases() -> Vec> { - vec![] + cases![] } fn erfc_cases() -> Vec> { - vec![] + cases![] } fn erfcf_cases() -> Vec> { - vec![] + cases![] } fn erff_cases() -> Vec> { - vec![] + cases![] } fn exp_cases() -> Vec> { - vec![] + cases![] } fn exp10_cases() -> Vec> { - vec![] + cases![] } fn exp10f_cases() -> Vec> { - vec![] + cases![] } fn exp2_cases() -> Vec> { - vec![] + cases![] } fn exp2f_cases() -> Vec> { - vec![] + cases![] } fn expf_cases() -> Vec> { - vec![] + cases![] } fn expm1_cases() -> Vec> { - vec![] + cases![] } fn expm1f_cases() -> Vec> { - vec![] + cases![] } fn fabs_cases() -> Vec> { - vec![] + cases![] } fn fabsf_cases() -> Vec> { - vec![] + cases![] } #[cfg(f128_enabled)] fn fabsf128_cases() -> Vec> { - vec![] + cases![] } #[cfg(f16_enabled)] fn fabsf16_cases() -> Vec> { - vec![] + cases![] } fn fdim_cases() -> Vec> { - vec![] + cases![] } fn fdimf_cases() -> Vec> { - vec![] + cases![] } #[cfg(f128_enabled)] fn fdimf128_cases() -> Vec> { - vec![] + cases![] } #[cfg(f16_enabled)] fn fdimf16_cases() -> Vec> { - vec![] + cases![] } fn floor_cases() -> Vec> { - vec![] + cases![] } fn floorf_cases() -> Vec> { - vec![] + cases![] } #[cfg(f128_enabled)] fn floorf128_cases() -> Vec> { - vec![] + cases![] } #[cfg(f16_enabled)] fn floorf16_cases() -> Vec> { - vec![] + cases![] } fn fma_cases() -> Vec> { - let mut v = vec![]; - TestCase::append_pairs( - &mut v, - &[ - // Previous failure with incorrect sign - ((5e-324, -5e-324, 0.0), Some(-0.0)), - ], - ); - v + cases![ + // Previous failure with incorrect sign + ((5e-324, -5e-324, 0.0), -0.0), + ] } fn fmaf_cases() -> Vec> { - let mut v = vec![]; - TestCase::append_pairs( - &mut v, - &[ - // Known rounding error for some implementations (notably MinGW) - ( - (-1.9369631e13f32, 2.1513551e-7, -1.7354427e-24), - Some(-4167095.8), - ), - ], - ); - v + cases![ + // Known rounding error for some implementations (notably MinGW) + ((-1.9369631e13f32, 2.1513551e-7, -1.7354427e-24), -4167095.8), + ] } #[cfg(f128_enabled)] fn fmaf128_cases() -> Vec> { - let mut v = vec![]; - TestCase::append_pairs( - &mut v, - &[ + cases![ + ( + // Tricky rounding case that previously failed in extensive tests ( - // Tricky rounding case that previously failed in extensive tests - ( - hf128!("-0x1.1966cc01966cc01966cc01966f06p-25"), - hf128!("-0x1.669933fe69933fe69933fe6997c9p-16358"), - hf128!("-0x0.000000000000000000000000048ap-16382"), - ), - Some(hf128!("0x0.c5171470a3ff5e0f68d751491b18p-16382")), + hf128!("-0x1.1966cc01966cc01966cc01966f06p-25"), + hf128!("-0x1.669933fe69933fe69933fe6997c9p-16358"), + hf128!("-0x0.000000000000000000000000048ap-16382"), ), + hf128!("0x0.c5171470a3ff5e0f68d751491b18p-16382") + ), + ( + // Subnormal edge case that caused a failure ( - // Subnormal edge case that caused a failure - ( - hf128!("0x0.7ffffffffffffffffffffffffff7p-16382"), - hf128!("0x1.ffffffffffffffffffffffffffffp-1"), - hf128!("0x0.8000000000000000000000000009p-16382"), - ), - Some(hf128!("0x1.0000000000000000000000000000p-16382")), + hf128!("0x0.7ffffffffffffffffffffffffff7p-16382"), + hf128!("0x1.ffffffffffffffffffffffffffffp-1"), + hf128!("0x0.8000000000000000000000000009p-16382"), ), - ], - ); - v + hf128!("0x1.0000000000000000000000000000p-16382") + ), + ] } #[cfg(f16_enabled)] fn fmaxf16_cases() -> Vec> { - vec![] + cases![] } fn fmaxf_cases() -> Vec> { - vec![] + cases![] } fn fmax_cases() -> Vec> { - vec![] + cases![] } #[cfg(f128_enabled)] fn fmaxf128_cases() -> Vec> { - vec![] + cases![] } #[cfg(f16_enabled)] fn fmaximumf16_cases() -> Vec> { - vec![] + cases![] } fn fmaximumf_cases() -> Vec> { - vec![] + cases![] } fn fmaximum_cases() -> Vec> { - vec![] + cases![] } #[cfg(f128_enabled)] fn fmaximumf128_cases() -> Vec> { - vec![] + cases![] } #[cfg(f16_enabled)] fn fmaximum_numf16_cases() -> Vec> { - vec![] + cases![] } fn fmaximum_numf_cases() -> Vec> { - vec![] + cases![] } fn fmaximum_num_cases() -> Vec> { - vec![] + cases![] } #[cfg(f128_enabled)] fn fmaximum_numf128_cases() -> Vec> { - vec![] + cases![] } #[cfg(f16_enabled)] fn fminf16_cases() -> Vec> { - vec![] + cases![] } fn fminf_cases() -> Vec> { - vec![] + cases![] } fn fmin_cases() -> Vec> { - vec![] + cases![] } #[cfg(f128_enabled)] fn fminf128_cases() -> Vec> { - vec![] + cases![] } #[cfg(f16_enabled)] fn fminimumf16_cases() -> Vec> { - vec![] + cases![] } fn fminimumf_cases() -> Vec> { - vec![] + cases![] } fn fminimum_cases() -> Vec> { - vec![] + cases![] } #[cfg(f128_enabled)] fn fminimumf128_cases() -> Vec> { - vec![] + cases![] } #[cfg(f16_enabled)] fn fminimum_numf16_cases() -> Vec> { - vec![] + cases![] } fn fminimum_numf_cases() -> Vec> { - vec![] + cases![] } fn fminimum_num_cases() -> Vec> { - vec![] + cases![] } #[cfg(f128_enabled)] fn fminimum_numf128_cases() -> Vec> { - vec![] + cases![] } fn fmod_cases() -> Vec> { - let mut v = vec![]; - TestCase::append_pairs( - &mut v, - &[ - // Previous failure with incorrect loop iteration - // - ((2.1, 3.123e-320), Some(2.0696e-320)), - ((2.1, 2.253547e-318), Some(1.772535e-318)), - ], - ); - v + cases![ + // Previous failure with incorrect loop iteration + // + ((2.1, 3.123e-320), 2.0696e-320), + ((2.1, 2.253547e-318), 1.772535e-318), + ] } fn fmodf_cases() -> Vec> { - let mut v = vec![]; - TestCase::append_pairs( - &mut v, - &[ - // Previous failure with incorrect loop iteration - // - ((2.1, 8.858e-42), Some(8.085e-42)), - ((2.1, 6.39164e-40), Some(6.1636e-40)), - ((5.5, 6.39164e-40), Some(4.77036e-40)), - ((-151.189, 6.39164e-40), Some(-5.64734e-40)), - ], - ); - v + cases![ + // Previous failure with incorrect loop iteration + // + ((2.1, 8.858e-42), 8.085e-42), + ((2.1, 6.39164e-40), 6.1636e-40), + ((5.5, 6.39164e-40), 4.77036e-40), + ((-151.189, 6.39164e-40), -5.64734e-40), + ] } #[cfg(f128_enabled)] fn fmodf128_cases() -> Vec> { - vec![] + cases![] } #[cfg(f16_enabled)] fn fmodf16_cases() -> Vec> { - vec![] + cases![] } #[cfg(f16_enabled)] fn frexpf16_cases() -> Vec> { - vec![] + cases![] } fn frexpf_cases() -> Vec> { - vec![] + cases![] } fn frexp_cases() -> Vec> { - vec![] + cases![] } #[cfg(f128_enabled)] fn frexpf128_cases() -> Vec> { - vec![] + cases![] } fn hypot_cases() -> Vec> { - vec![] + cases![] } fn hypotf_cases() -> Vec> { - vec![] + cases![] } #[cfg(f16_enabled)] fn ilogbf16_cases() -> Vec> { - vec![] + cases![] } fn ilogbf_cases() -> Vec> { - vec![] + cases![] } fn ilogb_cases() -> Vec> { - vec![] + cases![] } #[cfg(f128_enabled)] fn ilogbf128_cases() -> Vec> { - vec![] + cases![] } fn j0_cases() -> Vec> { - vec![] + cases![] } fn j0f_cases() -> Vec> { - vec![] + cases![] } fn j1_cases() -> Vec> { - vec![] + cases![] } fn j1f_cases() -> Vec> { - vec![] + cases![] } fn jn_cases() -> Vec> { - vec![] + cases![] } fn jnf_cases() -> Vec> { - vec![] + cases![] } fn ldexp_cases() -> Vec> { - vec![] + cases![] } fn ldexpf_cases() -> Vec> { - vec![] + cases![] } #[cfg(f128_enabled)] fn ldexpf128_cases() -> Vec> { - vec![] + cases![] } #[cfg(f16_enabled)] fn ldexpf16_cases() -> Vec> { - vec![] + cases![] } fn lgamma_cases() -> Vec> { - vec![] + cases![] } fn lgamma_r_cases() -> Vec> { - vec![] + cases![] } fn lgammaf_cases() -> Vec> { - vec![] + cases![] } fn lgammaf_r_cases() -> Vec> { - vec![] + cases![] } fn log_cases() -> Vec> { - vec![] + cases![] } fn log10_cases() -> Vec> { - vec![] + cases![] } fn log10f_cases() -> Vec> { - vec![] + cases![] } fn log1p_cases() -> Vec> { - vec![] + cases![] } fn log1pf_cases() -> Vec> { - vec![] + cases![] } fn log2_cases() -> Vec> { - vec![] + cases![] } fn log2f_cases() -> Vec> { - vec![] + cases![] } fn logf_cases() -> Vec> { - vec![] + cases![] } fn modf_cases() -> Vec> { - vec![] + cases![] } fn modff_cases() -> Vec> { - vec![] + cases![] } fn nextafter_cases() -> Vec> { - vec![] + cases![] } fn nextafterf_cases() -> Vec> { - vec![] + cases![] } fn pow_cases() -> Vec> { - vec![] + cases![] } fn powf_cases() -> Vec> { - vec![] + cases![] } fn remainder_cases() -> Vec> { - vec![] + cases![] } fn remainderf_cases() -> Vec> { - vec![] + cases![] } fn remquo_cases() -> Vec> { - vec![] + cases![] } fn remquof_cases() -> Vec> { - vec![] + cases![] } fn rint_cases() -> Vec> { - let mut v = vec![]; - TestCase::append_pairs( - &mut v, - &[ - // Known failure on i586 - #[cfg(not(x86_no_sse))] - ( - (hf64!("-0x1.e3f13ff995ffcp+38"),), - Some(hf64!("-0x1.e3f13ff994000p+38")), - ), - #[cfg(x86_no_sse)] - ( - (hf64!("-0x1.e3f13ff995ffcp+38"),), - Some(hf64!("-0x1.e3f13ff998000p+38")), - ), - ], - ); - v + cases![( + (hf64!("-0x1.e3f13ff995ffcp+38"),), + if cfg!(x86_no_sse) { + // XFAIL on i586 + hf64!("-0x1.e3f13ff998000p+38") + } else { + hf64!("-0x1.e3f13ff994000p+38") + } + ),] } fn rintf_cases() -> Vec> { - vec![] + cases![] } #[cfg(f128_enabled)] fn rintf128_cases() -> Vec> { - vec![] + cases![] } #[cfg(f16_enabled)] fn rintf16_cases() -> Vec> { - vec![] + cases![] } #[cfg(f16_enabled)] fn roundf16_cases() -> Vec> { - vec![] + cases![] } fn round_cases() -> Vec> { - vec![] + cases![] } fn roundf_cases() -> Vec> { - vec![] + cases![] } #[cfg(f128_enabled)] fn roundf128_cases() -> Vec> { - vec![] + cases![] } #[cfg(f16_enabled)] fn roundevenf16_cases() -> Vec> { - vec![] + cases![] } fn roundeven_cases() -> Vec> { - let mut v = vec![]; - TestCase::append_pairs( - &mut v, - &[ - // Known failure on i586 - #[cfg(not(x86_no_sse))] - ( - (hf64!("-0x1.e3f13ff995ffcp+38"),), - Some(hf64!("-0x1.e3f13ff994000p+38")), - ), - #[cfg(x86_no_sse)] - ( - (hf64!("-0x1.e3f13ff995ffcp+38"),), - Some(hf64!("-0x1.e3f13ff998000p+38")), - ), - ], - ); - v + cases![ + #[cfg(not(x86_no_sse))] + ( + (hf64!("-0x1.e3f13ff995ffcp+38"),), + if cfg!(x86_no_sse) { + // XFAIL on i586 + hf64!("-0x1.e3f13ff998000p+38") + } else { + hf64!("-0x1.e3f13ff994000p+38") + } + ), + ] } fn roundevenf_cases() -> Vec> { - vec![] + cases![] } #[cfg(f128_enabled)] fn roundevenf128_cases() -> Vec> { - vec![] + cases![] } fn scalbn_cases() -> Vec> { - vec![] + cases![] } fn scalbnf_cases() -> Vec> { - vec![] + cases![] } #[cfg(f128_enabled)] fn scalbnf128_cases() -> Vec> { - vec![] + cases![] } #[cfg(f16_enabled)] fn scalbnf16_cases() -> Vec> { - vec![] + cases![] } fn sin_cases() -> Vec> { - vec![] + cases![] } fn sincos_cases() -> Vec> { - vec![] + cases![] } fn sincosf_cases() -> Vec> { - vec![] + cases![] } fn sinf_cases() -> Vec> { - vec![] + cases![] } fn sinh_cases() -> Vec> { - vec![] + cases![] } fn sinhf_cases() -> Vec> { - vec![] + cases![] } fn sqrt_cases() -> Vec> { - vec![] + cases![] } fn sqrtf_cases() -> Vec> { - vec![] + cases![] } #[cfg(f128_enabled)] fn sqrtf128_cases() -> Vec> { - vec![] + cases![] } #[cfg(f16_enabled)] fn sqrtf16_cases() -> Vec> { - vec![] + cases![] } fn tan_cases() -> Vec> { - vec![] + cases![] } fn tanf_cases() -> Vec> { - vec![] + cases![] } fn tanh_cases() -> Vec> { - vec![] + cases![] } fn tanhf_cases() -> Vec> { - vec![] + cases![] } fn tgamma_cases() -> Vec> { - vec![] + cases![] } fn tgammaf_cases() -> Vec> { - vec![] + cases![] } fn trunc_cases() -> Vec> { - vec![] + cases![] } fn truncf_cases() -> Vec> { - vec![] + cases![] } #[cfg(f128_enabled)] fn truncf128_cases() -> Vec> { - vec![] + cases![] } #[cfg(f16_enabled)] fn truncf16_cases() -> Vec> { - vec![] + cases![] } fn y0_cases() -> Vec> { - vec![] + cases![] } fn y0f_cases() -> Vec> { - vec![] + cases![] } fn y1_cases() -> Vec> { - vec![] + cases![] } fn y1f_cases() -> Vec> { - vec![] + cases![] } fn yn_cases() -> Vec> { - vec![] + cases![] } fn ynf_cases() -> Vec> { - vec![] + cases![] } pub trait CaseListInput: MathOp + Sized { From 2b76b8eae8fedebf197aa461f2082ddaa83aa4c5 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Fri, 27 Mar 2026 17:42:31 -0500 Subject: [PATCH 043/183] test: Update precision defaults to be more accurate The current flow is somewhat confusing in what is an inaccuracy due to musl (either from implementation or from problems in the C ABI that we avoid) and what is an inaccuracy in our library on specific platforms. Clean up the structure here, which allows for some more narrow bounds. --- .../libm-test/src/precision.rs | 85 ++++++++++--------- 1 file changed, 45 insertions(+), 40 deletions(-) diff --git a/library/compiler-builtins/libm-test/src/precision.rs b/library/compiler-builtins/libm-test/src/precision.rs index f6b31f6e329a3..dbee911596c27 100644 --- a/library/compiler-builtins/libm-test/src/precision.rs +++ b/library/compiler-builtins/libm-test/src/precision.rs @@ -20,7 +20,7 @@ pub fn default_ulp(ctx: &CheckCtx) -> Option { Bn::Add | Bn::Sub | Bn::Mul | Bn::Div => 0, // FIXME(correctness): we need a better powi implementation (though this is no worse // than C). - Bn::Powi if ctx.fn_ident == Id::Powif64 => 10_000, + Bn::Powi if ctx.fn_ident == Id::Powif64 => 500_000, Bn::Powi => 1000, // Operations that only return non-float results @@ -112,7 +112,9 @@ pub fn default_ulp(ctx: &CheckCtx) -> Option { Bn::Tgamma => 20, }; - // These have a separate implementation on i586 + let mut orig_ulp = ulp; + + // These have a separate implementation on i586 which is more accurate. if cfg!(x86_no_sse) { match ctx.fn_ident { Id::Exp => ulp = 1, @@ -123,43 +125,17 @@ pub fn default_ulp(ctx: &CheckCtx) -> Option { Id::Exp10f => ulp = 0, _ => (), } - } - // There are some cases where musl's approximation is less accurate than ours. For these - // cases, increase the ULP. - if ctx.basis == Musl { - match ctx.base_name { - Bn::Cosh => ulp = 2, - Bn::Exp10 if usize::BITS < 64 => ulp = 4, - Bn::Tanh => ulp = 4, - _ => (), - } - - match ctx.fn_ident { - Id::Cbrt => ulp = 2, - // FIXME(#401): musl has an incorrect result here. - Id::Fdim => ulp = 2, - Id::Exp2f => ulp = 1, - Id::Expf => ulp = 1, - Id::Sincosf => ulp = 500, - Id::Tgamma => ulp = 20, - _ => (), - } - } + assert!(ulp <= orig_ulp, "pattern can be deleted {ctx:?}"); + orig_ulp = ulp; - if cfg!(target_arch = "x86") { + // Due to rust-lang/rust#114479 (unsound floating point behavior on x86 without SSE), the + // following operations have worse precision. match ctx.fn_ident { - // Input `fma(0.999999999999999, 1.0000000000000013, 0.0) = 1.0000000000000002` is - // incorrect on i586 and i686. + // FIXME: these need to be correctly rounded but are not, likely due to LLVM bugs + // around precision without SSE float ops. It may be worth looking into an assembly + // implementation. Id::Fma => ulp = 1, - _ => (), - } - } - - // In some cases, our implementation is less accurate than musl on i586. - if cfg!(x86_no_sse) { - match ctx.fn_ident { - // FIXME(#401): these need to be correctly rounded but are not. Id::Fmaf => ulp = 1, Id::Fdim => ulp = 1, Id::Round => ulp = 1, @@ -167,10 +143,38 @@ pub fn default_ulp(ctx: &CheckCtx) -> Option { Id::Asinh => ulp = 3, Id::Asinhf => ulp = 3, Id::Cbrt => ulp = 1, - Id::Log1p | Id::Log1pf => ulp = 2, + Id::Log1p => ulp = 2, + Id::Log1pf => ulp = 2, Id::Tan => ulp = 2, _ => (), } + + assert!(ulp >= orig_ulp, "pattern can be deleted {ctx:?}"); + orig_ulp = ulp; + } + + // There are some cases where musl's approximation is less accurate than ours, either due to + // the implementation itself or because of x87 inaccuracy problems. For these cases, increase + // the allowed ULP. + if ctx.basis == Musl { + match ctx.fn_ident { + // Musl probably runs into issues with the x87 ABI here which we don't have. + Id::Fma if cfg!(target_arch = "x86") => ulp = 1, + Id::Fdim => ulp = 2, + + Id::Asinhf => ulp = 3, + Id::Cbrt => ulp = 2, + Id::Cosh => ulp = 2, + Id::Coshf => ulp = 2, + Id::Exp10 if cfg!(x86_no_sse) => ulp = 4, + Id::Exp10f if cfg!(x86_no_sse) => ulp = 4, + Id::Exp2f => ulp = 1, + Id::Expf => ulp = 1, + Id::Tanh => ulp = 4, + _ => (), + } + + assert!(ulp >= orig_ulp, "pattern can be deleted {ctx:?}"); } Some(ulp) @@ -527,18 +531,19 @@ fn int_float_common( } // Our bessel functions blow up with large N values - if ctx.basis == Musl && (ctx.base_name == BaseName::Jn || ctx.base_name == BaseName::Yn) { + if ctx.base_name == BaseName::Jn || ctx.base_name == BaseName::Yn { if cfg!(x86_no_sse) { // Precision is especially bad on i586, not worth checking. return XFAIL_NOCHECK; } - if input.0 > 4000 { + if input.0 > 140 { return XFAIL_NOCHECK; - } else if input.0 > 100 { - return CheckAction::AssertWithUlp(2_000_000); + } else if input.0 > 80 { + return CheckAction::AssertWithUlp(10_000_000); } } + DEFAULT } From ef7d030120252489ce40cca6f4378c6b577b3dbf Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Sun, 29 Mar 2026 15:47:14 -0500 Subject: [PATCH 044/183] test: Allow special case overrides for list tests Currently an exact xfail result is needed on platforms that have variability (i586) but this is awkward to work with, especially for bessel functions. Change this to allow `SpecialCase` to be used. --- .../libm-test/src/generate/case_list.rs | 36 +++++++------------ .../libm-test/src/test_traits.rs | 2 -- 2 files changed, 12 insertions(+), 26 deletions(-) diff --git a/library/compiler-builtins/libm-test/src/generate/case_list.rs b/library/compiler-builtins/libm-test/src/generate/case_list.rs index 5be8f19e709d7..303f2caebfc11 100644 --- a/library/compiler-builtins/libm-test/src/generate/case_list.rs +++ b/library/compiler-builtins/libm-test/src/generate/case_list.rs @@ -1245,32 +1245,28 @@ fn remquof_cases() -> Vec> { cases![] } -fn rint_cases() -> Vec> { - cases![( - (hf64!("-0x1.e3f13ff995ffcp+38"),), - if cfg!(x86_no_sse) { - // XFAIL on i586 - hf64!("-0x1.e3f13ff998000p+38") - } else { - hf64!("-0x1.e3f13ff994000p+38") - } - ),] +#[cfg(f16_enabled)] +fn rintf16_cases() -> Vec> { + cases![] } fn rintf_cases() -> Vec> { cases![] } +fn rint_cases() -> Vec> { + cases![ + // Failure on i586 + ((-519629176421.49976,), -519629176421.0), + ] +} + #[cfg(f128_enabled)] fn rintf128_cases() -> Vec> { cases![] } #[cfg(f16_enabled)] -fn rintf16_cases() -> Vec> { - cases![] -} - #[cfg(f16_enabled)] fn roundf16_cases() -> Vec> { cases![] @@ -1296,16 +1292,8 @@ fn roundevenf16_cases() -> Vec> { fn roundeven_cases() -> Vec> { cases![ - #[cfg(not(x86_no_sse))] - ( - (hf64!("-0x1.e3f13ff995ffcp+38"),), - if cfg!(x86_no_sse) { - // XFAIL on i586 - hf64!("-0x1.e3f13ff998000p+38") - } else { - hf64!("-0x1.e3f13ff994000p+38") - } - ), + // Failure on i586 + ((-519629176421.49976,), -519629176421.0), ] } diff --git a/library/compiler-builtins/libm-test/src/test_traits.rs b/library/compiler-builtins/libm-test/src/test_traits.rs index 657190d80d710..ab91715c71243 100644 --- a/library/compiler-builtins/libm-test/src/test_traits.rs +++ b/library/compiler-builtins/libm-test/src/test_traits.rs @@ -290,8 +290,6 @@ where .expect("functions returning floats should have a default ulp set"); match SpecialCase::check_float(input, actual, expected, ctx) { - // Forbid overrides if the items came from an explicit list - _ if ctx.gen_kind == GeneratorKind::List => (), CheckAction::AssertSuccess => (), CheckAction::AssertFailure(msg) => assert_failure_msg = Some(msg), CheckAction::Custom(res) => return res, From 855bc875eca11a568de03aaf93403816d0615fec Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Sun, 29 Mar 2026 15:47:14 -0500 Subject: [PATCH 045/183] test: Add a number of specific test cases Most of these come from the list at [1], or from failures collected when updating test precision. [1]: https://github.com/rust-lang/compiler-builtins/issues/836 --- .../libm-test/src/generate/case_list.rs | 213 ++++++++++++++---- 1 file changed, 170 insertions(+), 43 deletions(-) diff --git a/library/compiler-builtins/libm-test/src/generate/case_list.rs b/library/compiler-builtins/libm-test/src/generate/case_list.rs index 303f2caebfc11..ea4b8028805a5 100644 --- a/library/compiler-builtins/libm-test/src/generate/case_list.rs +++ b/library/compiler-builtins/libm-test/src/generate/case_list.rs @@ -6,9 +6,9 @@ //! //! This is useful for adding regression tests or expected failures. -use libm::hf64; #[cfg(f128_enabled)] use libm::hf128; +use libm::{hf32, hf64}; use crate::{CheckBasis, CheckCtx, GeneratorKind, MathOp, op}; @@ -17,6 +17,20 @@ pub struct TestCase { pub output: Option, } +impl TestCase { + /// Turn into a different operation with the same types. + fn cast(self) -> TestCase + where + Op2::RustArgs: From, + Op2::RustRet: From, + { + TestCase { + input: self.input.into(), + output: self.output.map(Into::into), + } + } +} + macro_rules! cases { ( $( @@ -125,7 +139,10 @@ fn powif32_cases() -> Vec> { } fn powif64_cases() -> Vec> { - cases![] + cases![ + // High error + ((0.9999497584118668, -5858518), 6.823250355352412e127), + ] } #[cfg(f128_enabled)] @@ -701,11 +718,15 @@ fn asinf_cases() -> Vec> { cases![] } -fn asinh_cases() -> Vec> { - cases![] +fn asinhf_cases() -> Vec> { + cases![ + // Failure on i586 + ((-0.37330312), -0.3651353), + ((-0.421092), -0.40954682), + ] } -fn asinhf_cases() -> Vec> { +fn asinh_cases() -> Vec> { cases![] } @@ -830,7 +851,11 @@ fn exp2f_cases() -> Vec> { } fn expf_cases() -> Vec> { - cases![] + cases![ + ((hf32!("-0x1.2d245ap-8")), hf32!("0x1.fda718p-1")), + ((hf32!("0x1.db1b7ap-7")), hf32!("0x1.03bd22p+0")), + ((hf32!("-0x1.dc15fcp+5")), hf32!("0x1.1ae6e6p-86")), + ] } fn expm1_cases() -> Vec> { @@ -860,7 +885,30 @@ fn fabsf16_cases() -> Vec> { } fn fdim_cases() -> Vec> { - cases![] + cases![ + // Failures on i586 + ( + ( + hf64!("0x1.10d2f8a8dffd1p+355"), + hf64!("-0x1.5203b17e54a8cp+373") + ), + hf64!("0x1.5203f5b312d2fp+373") + ), + ( + ( + hf64!("0x1.9ffdf64f0d2f8p+294"), + hf64!("-0x1.71addd21280b5p+344") + ), + hf64!("0x1.71addd21280bbp+344") + ), + ( + ( + hf64!("0x1.f3600eb4ad0e0p-953"), + hf64!("-0x1.0c29b2b40023dp-976") + ), + hf64!("0x1.f36010cd00737p-953") + ), + ] } fn fdimf_cases() -> Vec> { @@ -895,17 +943,40 @@ fn floorf16_cases() -> Vec> { cases![] } -fn fma_cases() -> Vec> { +fn fmaf_cases() -> Vec> { cases![ - // Previous failure with incorrect sign - ((5e-324, -5e-324, 0.0), -0.0), + // Known rounding error for some implementations (notably MinGW) + ((-1.9369631e13f32, 2.1513551e-7, -1.7354427e-24), -4167095.8), + // Failure on i586 + ( + ( + hf32!("-0x1.c92494p+109"), + hf32!("-0x0.000018p-126"), + hf32!("-0x1.6db6f0p-91"), + ), + hf32!("0x1.56db6ep-36") + ), ] } -fn fmaf_cases() -> Vec> { +fn fma_cases() -> Vec> { cases![ - // Known rounding error for some implementations (notably MinGW) - ((-1.9369631e13f32, 2.1513551e-7, -1.7354427e-24), -4167095.8), + // Previous failure with incorrect sign + ((5e-324, -5e-324, 0.0), -0.0), + // Failure on i586 + ( + (0.999999999999999, 1.0000000000000013, 0.0), + 1.0000000000000002 + ), + // Failure on musl i686/i586 + ( + ( + hf64!("0x0.0000000100001p-1022"), + hf64!("0x1.ffffffffffffbp+1023"), + hf64!("0x0p+0") + ), + hf64!("0x1.00000fffffffdp-30") + ) ] } @@ -1131,12 +1202,16 @@ fn j1f_cases() -> Vec> { cases![] } -fn jn_cases() -> Vec> { +fn jnf_cases() -> Vec> { cases![] } -fn jnf_cases() -> Vec> { - cases![] +fn jn_cases() -> Vec> { + cases![ + // Inputs that produce high errors + ((190, 1005.366268038242), 7.328620335959289e-10), + ((238, -311.0349), 7.270196433535006e-8), + ] } fn ldexp_cases() -> Vec> { @@ -1161,11 +1236,14 @@ fn lgamma_cases() -> Vec> { cases![] } -fn lgamma_r_cases() -> Vec> { - cases![] +fn lgammaf_cases() -> Vec> { + cases![ + // High error + ((-4.933393,), -1.9580022), + ] } -fn lgammaf_cases() -> Vec> { +fn lgamma_r_cases() -> Vec> { cases![] } @@ -1185,12 +1263,23 @@ fn log10f_cases() -> Vec> { cases![] } -fn log1p_cases() -> Vec> { - cases![] +fn log1pf_cases() -> Vec> { + cases![ + // Musl failures on i586 + ((hf32!("-0x1.8292f6p-2")), hf32!("-0x1.e56918p-2")), + ((hf32!("0x1.12d15ep-1")), hf32!("0x1.b7fbf8p-2")), + ((hf32!("-0x1.904ebep-2")), hf32!("-0x1.fbb6cap-2")), + ] } -fn log1pf_cases() -> Vec> { - cases![] +fn log1p_cases() -> Vec> { + cases![ + // Musl failure on i586 + ( + (hf64!("-0x1.9094dbf7f2e85p-2"),), + hf64!("-0x1.fc29f046c88a1p-2") + ), + ] } fn log2_cases() -> Vec> { @@ -1247,33 +1336,45 @@ fn remquof_cases() -> Vec> { #[cfg(f16_enabled)] fn rintf16_cases() -> Vec> { - cases![] + // Out rint doesn't respect rounding modes so it is the same as roundeven + roundevenf16_cases() + .into_iter() + .map(TestCase::cast) + .collect() } fn rintf_cases() -> Vec> { - cases![] + // Out rint doesn't respect rounding modes so it is the same as roundeven + roundevenf_cases().into_iter().map(TestCase::cast).collect() } fn rint_cases() -> Vec> { - cases![ - // Failure on i586 - ((-519629176421.49976,), -519629176421.0), - ] + // Out rint doesn't respect rounding modes so it is the same as roundeven + roundeven_cases().into_iter().map(TestCase::cast).collect() } #[cfg(f128_enabled)] fn rintf128_cases() -> Vec> { - cases![] + // Out rint doesn't respect rounding modes so it is the same as roundeven + roundevenf128_cases() + .into_iter() + .map(TestCase::cast) + .collect() } -#[cfg(f16_enabled)] #[cfg(f16_enabled)] fn roundf16_cases() -> Vec> { cases![] } fn round_cases() -> Vec> { - cases![] + cases![ + // Failure on i586 + ( + (hf64!("0x1.9efc6a203d4a9p+52"),), + hf64!("0x1.9efc6a203d4a9p+52") + ) + ] } fn roundf_cases() -> Vec> { @@ -1290,17 +1391,21 @@ fn roundevenf16_cases() -> Vec> { cases![] } +fn roundevenf_cases() -> Vec> { + cases![] +} + fn roundeven_cases() -> Vec> { cases![ // Failure on i586 ((-519629176421.49976,), -519629176421.0), + // Failures with a previous algorithm + ((-849751480.5001163,), -849751481.0), + ((-12493089.499809155,), -12493089.0), + ((-1308.5000830345912,), -1309.0), ] } -fn roundevenf_cases() -> Vec> { - cases![] -} - #[cfg(f128_enabled)] fn roundevenf128_cases() -> Vec> { cases![] @@ -1366,16 +1471,33 @@ fn sqrtf16_cases() -> Vec> { cases![] } -fn tan_cases() -> Vec> { +fn tanf_cases() -> Vec> { cases![] } -fn tanf_cases() -> Vec> { - cases![] +fn tan_cases() -> Vec> { + cases![ + // Musl failures on i586 + ( + (hf64!("0x1.fffffffffffafp+1023"),), + hf64!("0x1.c573c6dd8c00ap+0") + ), + ( + (hf64!("0x1.fffffffffffafp+1023"),), + hf64!("0x1.c573c6dd8c00ap+0") + ), + ( + (hf64!("-0x1.0b10f6eaf2ca0p+883"),), + hf64!("0x1.cefbd167e2402p+0") + ), + ] } fn tanh_cases() -> Vec> { - cases![] + cases![( + (hf64!("0x1.fbfdb8b31b9b4p-3"),), + hf64!("0x1.f1d2bcb4e1b45p-3") + )] } fn tanhf_cases() -> Vec> { @@ -1424,12 +1546,17 @@ fn y1f_cases() -> Vec> { cases![] } -fn yn_cases() -> Vec> { +fn ynf_cases() -> Vec> { cases![] } -fn ynf_cases() -> Vec> { - cases![] +fn yn_cases() -> Vec> { + cases![ + // Inputs that should be finite but tend to round to infinity + ((228, 120.75621), -3.3293829e38), + ((148, 61.379253), -3.2585946e38), + ((184, 87.26689), -3.2943882e38), + ] } pub trait CaseListInput: MathOp + Sized { From 220bcdaee76ef0195ad5d5e8b9826b8987b60870 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Sun, 29 Mar 2026 23:19:57 -0500 Subject: [PATCH 046/183] libm: Prepare to split files in `arch/` Move arch-specific files to an arch-named directory with a name based on whatever most of the operations in the file are, in preparation for splitting the file up. Moving to these names in a separate commit is done as a git hack to keep as much of the blame intact as possible, without needing `-M` or `-C`. Note that libm does not build after this commit. The next commit resolves this. --- .../libm/src/math/arch/{aarch64.rs => aarch64/rounding.rs} | 0 .../libm/src/math/arch/{i586.rs => i586/exp_all.rs} | 0 .../libm/src/math/arch/{wasm32.rs => wasm32/rounding.rs} | 0 .../compiler-builtins/libm/src/math/arch/{x86.rs => x86/sqrt.rs} | 0 4 files changed, 0 insertions(+), 0 deletions(-) rename library/compiler-builtins/libm/src/math/arch/{aarch64.rs => aarch64/rounding.rs} (100%) rename library/compiler-builtins/libm/src/math/arch/{i586.rs => i586/exp_all.rs} (100%) rename library/compiler-builtins/libm/src/math/arch/{wasm32.rs => wasm32/rounding.rs} (100%) rename library/compiler-builtins/libm/src/math/arch/{x86.rs => x86/sqrt.rs} (100%) diff --git a/library/compiler-builtins/libm/src/math/arch/aarch64.rs b/library/compiler-builtins/libm/src/math/arch/aarch64/rounding.rs similarity index 100% rename from library/compiler-builtins/libm/src/math/arch/aarch64.rs rename to library/compiler-builtins/libm/src/math/arch/aarch64/rounding.rs diff --git a/library/compiler-builtins/libm/src/math/arch/i586.rs b/library/compiler-builtins/libm/src/math/arch/i586/exp_all.rs similarity index 100% rename from library/compiler-builtins/libm/src/math/arch/i586.rs rename to library/compiler-builtins/libm/src/math/arch/i586/exp_all.rs diff --git a/library/compiler-builtins/libm/src/math/arch/wasm32.rs b/library/compiler-builtins/libm/src/math/arch/wasm32/rounding.rs similarity index 100% rename from library/compiler-builtins/libm/src/math/arch/wasm32.rs rename to library/compiler-builtins/libm/src/math/arch/wasm32/rounding.rs diff --git a/library/compiler-builtins/libm/src/math/arch/x86.rs b/library/compiler-builtins/libm/src/math/arch/x86/sqrt.rs similarity index 100% rename from library/compiler-builtins/libm/src/math/arch/x86.rs rename to library/compiler-builtins/libm/src/math/arch/x86/sqrt.rs From d11c9f69fb0af75a5b3ebe16b8b153e8c28888bb Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Sun, 29 Mar 2026 23:33:42 -0500 Subject: [PATCH 047/183] libm: Split files in `arch/` Split functions across files so `arch/` closer mirrors the top-level `math` directory. Similar operations are still kept in the same file since many of these functions are pretty tiny. This will make it a bit easier to extend assembly implementations without winding up with cluttered files, and helps avoid false positives in the ci-util.py checks for changed operations. --- .../etc/function-definitions.json | 48 ++++++------ .../libm/src/math/arch/aarch64/fma.rs | 29 +++++++ .../libm/src/math/arch/aarch64/mod.rs | 13 ++++ .../libm/src/math/arch/aarch64/rounding.rs | 78 ++----------------- .../libm/src/math/arch/aarch64/sqrt.rs | 39 ++++++++++ .../libm/src/math/arch/i586/exp_all.rs | 62 --------------- .../libm/src/math/arch/i586/mod.rs | 14 ++++ .../libm/src/math/arch/i586/rounding.rs | 53 +++++++++++++ .../libm/src/math/arch/wasm32/fabs.rs | 7 ++ .../libm/src/math/arch/wasm32/mod.rs | 10 +++ .../libm/src/math/arch/wasm32/rounding.rs | 16 ---- .../libm/src/math/arch/wasm32/sqrt.rs | 7 ++ .../libm/src/math/arch/x86/detect.rs | 4 +- .../libm/src/math/arch/x86/mod.rs | 8 ++ .../libm/src/math/arch/x86/sqrt.rs | 7 -- 15 files changed, 211 insertions(+), 184 deletions(-) create mode 100644 library/compiler-builtins/libm/src/math/arch/aarch64/fma.rs create mode 100644 library/compiler-builtins/libm/src/math/arch/aarch64/mod.rs create mode 100644 library/compiler-builtins/libm/src/math/arch/aarch64/sqrt.rs create mode 100644 library/compiler-builtins/libm/src/math/arch/i586/mod.rs create mode 100644 library/compiler-builtins/libm/src/math/arch/i586/rounding.rs create mode 100644 library/compiler-builtins/libm/src/math/arch/wasm32/fabs.rs create mode 100644 library/compiler-builtins/libm/src/math/arch/wasm32/mod.rs create mode 100644 library/compiler-builtins/libm/src/math/arch/wasm32/sqrt.rs create mode 100644 library/compiler-builtins/libm/src/math/arch/x86/mod.rs diff --git a/library/compiler-builtins/etc/function-definitions.json b/library/compiler-builtins/etc/function-definitions.json index 6bd395a84b66f..6792294d538e3 100644 --- a/library/compiler-builtins/etc/function-definitions.json +++ b/library/compiler-builtins/etc/function-definitions.json @@ -98,8 +98,8 @@ }, "ceil": { "sources": [ - "libm/src/math/arch/i586.rs", - "libm/src/math/arch/wasm32.rs", + "libm/src/math/arch/i586/rounding.rs", + "libm/src/math/arch/wasm32/rounding.rs", "libm/src/math/ceil.rs", "libm/src/math/generic/ceil.rs" ], @@ -107,7 +107,7 @@ }, "ceilf": { "sources": [ - "libm/src/math/arch/wasm32.rs", + "libm/src/math/arch/wasm32/rounding.rs", "libm/src/math/ceil.rs", "libm/src/math/generic/ceil.rs" ], @@ -253,7 +253,7 @@ }, "fabs": { "sources": [ - "libm/src/math/arch/wasm32.rs", + "libm/src/math/arch/wasm32/fabs.rs", "libm/src/math/fabs.rs", "libm/src/math/generic/fabs.rs" ], @@ -261,7 +261,7 @@ }, "fabsf": { "sources": [ - "libm/src/math/arch/wasm32.rs", + "libm/src/math/arch/wasm32/fabs.rs", "libm/src/math/fabs.rs", "libm/src/math/generic/fabs.rs" ], @@ -311,8 +311,8 @@ }, "floor": { "sources": [ - "libm/src/math/arch/i586.rs", - "libm/src/math/arch/wasm32.rs", + "libm/src/math/arch/i586/rounding.rs", + "libm/src/math/arch/wasm32/rounding.rs", "libm/src/math/floor.rs", "libm/src/math/generic/floor.rs" ], @@ -320,7 +320,7 @@ }, "floorf": { "sources": [ - "libm/src/math/arch/wasm32.rs", + "libm/src/math/arch/wasm32/rounding.rs", "libm/src/math/floor.rs", "libm/src/math/generic/floor.rs" ], @@ -342,7 +342,7 @@ }, "fma": { "sources": [ - "libm/src/math/arch/aarch64.rs", + "libm/src/math/arch/aarch64/fma.rs", "libm/src/math/arch/x86/fma.rs", "libm/src/math/fma.rs" ], @@ -350,7 +350,7 @@ }, "fmaf": { "sources": [ - "libm/src/math/arch/aarch64.rs", + "libm/src/math/arch/aarch64/fma.rs", "libm/src/math/arch/x86/fma.rs", "libm/src/math/fma.rs" ], @@ -820,16 +820,16 @@ }, "rint": { "sources": [ - "libm/src/math/arch/aarch64.rs", - "libm/src/math/arch/wasm32.rs", + "libm/src/math/arch/aarch64/rounding.rs", + "libm/src/math/arch/wasm32/rounding.rs", "libm/src/math/rint.rs" ], "type": "f64" }, "rintf": { "sources": [ - "libm/src/math/arch/aarch64.rs", - "libm/src/math/arch/wasm32.rs", + "libm/src/math/arch/aarch64/rounding.rs", + "libm/src/math/arch/wasm32/rounding.rs", "libm/src/math/rint.rs" ], "type": "f32" @@ -842,7 +842,7 @@ }, "rintf16": { "sources": [ - "libm/src/math/arch/aarch64.rs", + "libm/src/math/arch/aarch64/rounding.rs", "libm/src/math/rint.rs" ], "type": "f16" @@ -965,9 +965,9 @@ }, "sqrt": { "sources": [ - "libm/src/math/arch/aarch64.rs", - "libm/src/math/arch/wasm32.rs", - "libm/src/math/arch/x86.rs", + "libm/src/math/arch/aarch64/sqrt.rs", + "libm/src/math/arch/wasm32/sqrt.rs", + "libm/src/math/arch/x86/sqrt.rs", "libm/src/math/generic/sqrt.rs", "libm/src/math/sqrt.rs" ], @@ -975,9 +975,9 @@ }, "sqrtf": { "sources": [ - "libm/src/math/arch/aarch64.rs", - "libm/src/math/arch/wasm32.rs", - "libm/src/math/arch/x86.rs", + "libm/src/math/arch/aarch64/sqrt.rs", + "libm/src/math/arch/wasm32/sqrt.rs", + "libm/src/math/arch/x86/sqrt.rs", "libm/src/math/generic/sqrt.rs", "libm/src/math/sqrt.rs" ], @@ -992,7 +992,7 @@ }, "sqrtf16": { "sources": [ - "libm/src/math/arch/aarch64.rs", + "libm/src/math/arch/aarch64/sqrt.rs", "libm/src/math/generic/sqrt.rs", "libm/src/math/sqrt.rs" ], @@ -1036,7 +1036,7 @@ }, "trunc": { "sources": [ - "libm/src/math/arch/wasm32.rs", + "libm/src/math/arch/wasm32/rounding.rs", "libm/src/math/generic/trunc.rs", "libm/src/math/trunc.rs" ], @@ -1044,7 +1044,7 @@ }, "truncf": { "sources": [ - "libm/src/math/arch/wasm32.rs", + "libm/src/math/arch/wasm32/rounding.rs", "libm/src/math/generic/trunc.rs", "libm/src/math/trunc.rs" ], diff --git a/library/compiler-builtins/libm/src/math/arch/aarch64/fma.rs b/library/compiler-builtins/libm/src/math/arch/aarch64/fma.rs new file mode 100644 index 0000000000000..9fd574fad37d2 --- /dev/null +++ b/library/compiler-builtins/libm/src/math/arch/aarch64/fma.rs @@ -0,0 +1,29 @@ +use core::arch::asm; + +pub fn fmaf(mut x: f32, y: f32, z: f32) -> f32 { + // SAFETY: `fmadd` is available with neon and has no side effects. + unsafe { + asm!( + "fmadd {x:s}, {x:s}, {y:s}, {z:s}", + x = inout(vreg) x, + y = in(vreg) y, + z = in(vreg) z, + options(nomem, nostack, pure) + ); + } + x +} + +pub fn fma(mut x: f64, y: f64, z: f64) -> f64 { + // SAFETY: `fmadd` is available with neon and has no side effects. + unsafe { + asm!( + "fmadd {x:d}, {x:d}, {y:d}, {z:d}", + x = inout(vreg) x, + y = in(vreg) y, + z = in(vreg) z, + options(nomem, nostack, pure) + ); + } + x +} diff --git a/library/compiler-builtins/libm/src/math/arch/aarch64/mod.rs b/library/compiler-builtins/libm/src/math/arch/aarch64/mod.rs new file mode 100644 index 0000000000000..0192a3d442aec --- /dev/null +++ b/library/compiler-builtins/libm/src/math/arch/aarch64/mod.rs @@ -0,0 +1,13 @@ +//! Architecture-specific support for aarch64 with neon. + +mod fma; +mod rounding; +mod sqrt; + +pub use fma::{fma, fmaf}; +#[cfg(all(f16_enabled, target_feature = "fp16"))] +pub use rounding::rintf16; +pub use rounding::{rint, rintf}; +#[cfg(all(f16_enabled, target_feature = "fp16"))] +pub use sqrt::sqrtf16; +pub use sqrt::{sqrt, sqrtf}; diff --git a/library/compiler-builtins/libm/src/math/arch/aarch64/rounding.rs b/library/compiler-builtins/libm/src/math/arch/aarch64/rounding.rs index 8896804b50403..6549497d9cd7d 100644 --- a/library/compiler-builtins/libm/src/math/arch/aarch64/rounding.rs +++ b/library/compiler-builtins/libm/src/math/arch/aarch64/rounding.rs @@ -1,41 +1,11 @@ -//! Architecture-specific support for aarch64 with neon. +//! NB: `frintx` is technically the correct instruction for C's `rint`. However, in Rust (and LLVM +//! by default), `rint` is identical to `roundeven` (no fpenv interaction) so we use the +//! side-effect-free `frintn`. +//! +//! In general, C code that calls Rust's libm should assume that fpenv is ignored. use core::arch::asm; -pub fn fma(mut x: f64, y: f64, z: f64) -> f64 { - // SAFETY: `fmadd` is available with neon and has no side effects. - unsafe { - asm!( - "fmadd {x:d}, {x:d}, {y:d}, {z:d}", - x = inout(vreg) x, - y = in(vreg) y, - z = in(vreg) z, - options(nomem, nostack, pure) - ); - } - x -} - -pub fn fmaf(mut x: f32, y: f32, z: f32) -> f32 { - // SAFETY: `fmadd` is available with neon and has no side effects. - unsafe { - asm!( - "fmadd {x:s}, {x:s}, {y:s}, {z:s}", - x = inout(vreg) x, - y = in(vreg) y, - z = in(vreg) z, - options(nomem, nostack, pure) - ); - } - x -} - -// NB: `frintx` is technically the correct instruction for C's `rint`. However, in Rust (and LLVM -// by default), `rint` is identical to `roundeven` (no fpenv interaction) so we use the -// side-effect-free `frintn`. -// -// In general, C code that calls Rust's libm should assume that fpenv is ignored. - pub fn rint(mut x: f64) -> f64 { // SAFETY: `frintn` is available with neon and has no side effects. // @@ -81,41 +51,3 @@ pub fn rintf16(mut x: f16) -> f16 { } x } - -pub fn sqrt(mut x: f64) -> f64 { - // SAFETY: `fsqrt` is available with neon and has no side effects. - unsafe { - asm!( - "fsqrt {x:d}, {x:d}", - x = inout(vreg) x, - options(nomem, nostack, pure) - ); - } - x -} - -pub fn sqrtf(mut x: f32) -> f32 { - // SAFETY: `fsqrt` is available with neon and has no side effects. - unsafe { - asm!( - "fsqrt {x:s}, {x:s}", - x = inout(vreg) x, - options(nomem, nostack, pure) - ); - } - x -} - -#[cfg(all(f16_enabled, target_feature = "fp16"))] -pub fn sqrtf16(mut x: f16) -> f16 { - // SAFETY: `fsqrt` is available for `f16` with `fp16` (implies `neon`) and has no - // side effects. - unsafe { - asm!( - "fsqrt {x:h}, {x:h}", - x = inout(vreg) x, - options(nomem, nostack, pure) - ); - } - x -} diff --git a/library/compiler-builtins/libm/src/math/arch/aarch64/sqrt.rs b/library/compiler-builtins/libm/src/math/arch/aarch64/sqrt.rs new file mode 100644 index 0000000000000..8a08ab3292fc2 --- /dev/null +++ b/library/compiler-builtins/libm/src/math/arch/aarch64/sqrt.rs @@ -0,0 +1,39 @@ +use core::arch::asm; + +pub fn sqrtf(mut x: f32) -> f32 { + // SAFETY: `fsqrt` is available with neon and has no side effects. + unsafe { + asm!( + "fsqrt {x:s}, {x:s}", + x = inout(vreg) x, + options(nomem, nostack, pure) + ); + } + x +} + +pub fn sqrt(mut x: f64) -> f64 { + // SAFETY: `fsqrt` is available with neon and has no side effects. + unsafe { + asm!( + "fsqrt {x:d}, {x:d}", + x = inout(vreg) x, + options(nomem, nostack, pure) + ); + } + x +} + +#[cfg(all(f16_enabled, target_feature = "fp16"))] +pub fn sqrtf16(mut x: f16) -> f16 { + // SAFETY: `fsqrt` is available for `f16` with `fp16` (implies `neon`) and has no + // side effects. + unsafe { + asm!( + "fsqrt {x:h}, {x:h}", + x = inout(vreg) x, + options(nomem, nostack, pure) + ); + } + x +} diff --git a/library/compiler-builtins/libm/src/math/arch/i586/exp_all.rs b/library/compiler-builtins/libm/src/math/arch/i586/exp_all.rs index d9bb93fbf5852..020b5c057daaf 100644 --- a/library/compiler-builtins/libm/src/math/arch/i586/exp_all.rs +++ b/library/compiler-builtins/libm/src/math/arch/i586/exp_all.rs @@ -1,65 +1,3 @@ -//! Architecture-specific support for x86-32 without SSE2 -//! -//! We use an alternative implementation on x86, because the -//! main implementation fails with the x87 FPU used by -//! debian i386, probably due to excess precision issues. -//! -//! See https://github.com/rust-lang/compiler-builtins/pull/976 for discussion on why these -//! functions are implemented in this way. - -pub fn ceil(mut x: f64) -> f64 { - unsafe { - core::arch::asm!( - "fld qword ptr [{x}]", - // Save the FPU control word, using `x` as scratch space. - "fstcw [{x}]", - // Set rounding control to 0b10 (+∞). - "mov word ptr [{x} + 2], 0x0b7f", - "fldcw [{x} + 2]", - // Round. - "frndint", - // Restore FPU control word. - "fldcw [{x}]", - // Save rounded value to memory. - "fstp qword ptr [{x}]", - x = in(reg) &mut x, - // All the x87 FPU stack is used, all registers must be clobbered - out("st(0)") _, out("st(1)") _, - out("st(2)") _, out("st(3)") _, - out("st(4)") _, out("st(5)") _, - out("st(6)") _, out("st(7)") _, - options(nostack), - ); - } - x -} - -pub fn floor(mut x: f64) -> f64 { - unsafe { - core::arch::asm!( - "fld qword ptr [{x}]", - // Save the FPU control word, using `x` as scratch space. - "fstcw [{x}]", - // Set rounding control to 0b01 (-∞). - "mov word ptr [{x} + 2], 0x077f", - "fldcw [{x} + 2]", - // Round. - "frndint", - // Restore FPU control word. - "fldcw [{x}]", - // Save rounded value to memory. - "fstp qword ptr [{x}]", - x = in(reg) &mut x, - // All the x87 FPU stack is used, all registers must be clobbered - out("st(0)") _, out("st(1)") _, - out("st(2)") _, out("st(3)") _, - out("st(4)") _, out("st(5)") _, - out("st(6)") _, out("st(7)") _, - options(nostack), - ); - } - x -} /// Implements the exponential functions with `x87` assembly. /// /// This relies on the instruction `f2xm1`, which computes `2^x - 1` (for diff --git a/library/compiler-builtins/libm/src/math/arch/i586/mod.rs b/library/compiler-builtins/libm/src/math/arch/i586/mod.rs new file mode 100644 index 0000000000000..fa8b798757640 --- /dev/null +++ b/library/compiler-builtins/libm/src/math/arch/i586/mod.rs @@ -0,0 +1,14 @@ +//! Architecture-specific support for x86-32 without SSE2 +//! +//! We use an alternative implementation on x86, because the +//! main implementation fails with the x87 FPU used by +//! debian i386, probably due to excess precision issues. +//! +//! See https://github.com/rust-lang/compiler-builtins/pull/976 for discussion on why these +//! functions are implemented in this way. + +mod exp_all; +mod rounding; + +pub use exp_all::{x87_exp, x87_exp2, x87_exp2f, x87_exp10, x87_exp10f, x87_expf}; +pub use rounding::{ceil, floor}; diff --git a/library/compiler-builtins/libm/src/math/arch/i586/rounding.rs b/library/compiler-builtins/libm/src/math/arch/i586/rounding.rs new file mode 100644 index 0000000000000..3981e3d109ff8 --- /dev/null +++ b/library/compiler-builtins/libm/src/math/arch/i586/rounding.rs @@ -0,0 +1,53 @@ +pub fn ceil(mut x: f64) -> f64 { + unsafe { + core::arch::asm!( + "fld qword ptr [{x}]", + // Save the FPU control word, using `x` as scratch space. + "fstcw [{x}]", + // Set rounding control to 0b10 (+∞). + "mov word ptr [{x} + 2], 0x0b7f", + "fldcw [{x} + 2]", + // Round. + "frndint", + // Restore FPU control word. + "fldcw [{x}]", + // Save rounded value to memory. + "fstp qword ptr [{x}]", + x = in(reg) &mut x, + // All the x87 FPU stack is used, all registers must be clobbered + out("st(0)") _, out("st(1)") _, + out("st(2)") _, out("st(3)") _, + out("st(4)") _, out("st(5)") _, + out("st(6)") _, out("st(7)") _, + options(nostack), + ); + } + x +} + +pub fn floor(mut x: f64) -> f64 { + unsafe { + core::arch::asm!( + "fld qword ptr [{x}]", + // Save the FPU control word, using `x` as scratch space. + "fstcw [{x}]", + // Set rounding control to 0b01 (-∞). + "mov word ptr [{x} + 2], 0x077f", + "fldcw [{x} + 2]", + // Round. + "frndint", + // Restore FPU control word. + "fldcw [{x}]", + // Save rounded value to memory. + "fstp qword ptr [{x}]", + x = in(reg) &mut x, + // All the x87 FPU stack is used, all registers must be clobbered + out("st(0)") _, out("st(1)") _, + out("st(2)") _, out("st(3)") _, + out("st(4)") _, out("st(5)") _, + out("st(6)") _, out("st(7)") _, + options(nostack), + ); + } + x +} diff --git a/library/compiler-builtins/libm/src/math/arch/wasm32/fabs.rs b/library/compiler-builtins/libm/src/math/arch/wasm32/fabs.rs new file mode 100644 index 0000000000000..1f5ff3f28131b --- /dev/null +++ b/library/compiler-builtins/libm/src/math/arch/wasm32/fabs.rs @@ -0,0 +1,7 @@ +pub fn fabsf(x: f32) -> f32 { + x.abs() +} + +pub fn fabs(x: f64) -> f64 { + x.abs() +} diff --git a/library/compiler-builtins/libm/src/math/arch/wasm32/mod.rs b/library/compiler-builtins/libm/src/math/arch/wasm32/mod.rs new file mode 100644 index 0000000000000..b262e0108155e --- /dev/null +++ b/library/compiler-builtins/libm/src/math/arch/wasm32/mod.rs @@ -0,0 +1,10 @@ +//! Wasm has builtins for simple float operations. Use the unstable `core::arch` intrinsics which +//! are significantly faster than soft float operations. + +mod fabs; +mod rounding; +mod sqrt; + +pub use fabs::{fabs, fabsf}; +pub use rounding::{ceil, ceilf, floor, floorf, rint, rintf, trunc, truncf}; +pub use sqrt::{sqrt, sqrtf}; diff --git a/library/compiler-builtins/libm/src/math/arch/wasm32/rounding.rs b/library/compiler-builtins/libm/src/math/arch/wasm32/rounding.rs index de80c8a581726..35196f0d743cf 100644 --- a/library/compiler-builtins/libm/src/math/arch/wasm32/rounding.rs +++ b/library/compiler-builtins/libm/src/math/arch/wasm32/rounding.rs @@ -9,14 +9,6 @@ pub fn ceilf(x: f32) -> f32 { core::arch::wasm32::f32_ceil(x) } -pub fn fabs(x: f64) -> f64 { - x.abs() -} - -pub fn fabsf(x: f32) -> f32 { - x.abs() -} - pub fn floor(x: f64) -> f64 { core::arch::wasm32::f64_floor(x) } @@ -33,14 +25,6 @@ pub fn rintf(x: f32) -> f32 { core::arch::wasm32::f32_nearest(x) } -pub fn sqrt(x: f64) -> f64 { - core::arch::wasm32::f64_sqrt(x) -} - -pub fn sqrtf(x: f32) -> f32 { - core::arch::wasm32::f32_sqrt(x) -} - pub fn trunc(x: f64) -> f64 { core::arch::wasm32::f64_trunc(x) } diff --git a/library/compiler-builtins/libm/src/math/arch/wasm32/sqrt.rs b/library/compiler-builtins/libm/src/math/arch/wasm32/sqrt.rs new file mode 100644 index 0000000000000..1d73e4ddcfe96 --- /dev/null +++ b/library/compiler-builtins/libm/src/math/arch/wasm32/sqrt.rs @@ -0,0 +1,7 @@ +pub fn sqrtf(x: f32) -> f32 { + core::arch::wasm32::f32_sqrt(x) +} + +pub fn sqrt(x: f64) -> f64 { + core::arch::wasm32::f64_sqrt(x) +} diff --git a/library/compiler-builtins/libm/src/math/arch/x86/detect.rs b/library/compiler-builtins/libm/src/math/arch/x86/detect.rs index ca785470b806d..983818b5b5e47 100644 --- a/library/compiler-builtins/libm/src/math/arch/x86/detect.rs +++ b/library/compiler-builtins/libm/src/math/arch/x86/detect.rs @@ -1,5 +1,5 @@ -// Using runtime feature detection requires atomics. Currently there are no x86 targets -// that support sse but not `AtomicPtr`. +//! Using runtime feature detection requires atomics. Currently there are no x86 targets +//! that support sse but not `AtomicPtr`. #[cfg(target_arch = "x86")] use core::arch::x86::{__cpuid, __cpuid_count, _xgetbv, CpuidResult}; diff --git a/library/compiler-builtins/libm/src/math/arch/x86/mod.rs b/library/compiler-builtins/libm/src/math/arch/x86/mod.rs new file mode 100644 index 0000000000000..279bf35b9c9e0 --- /dev/null +++ b/library/compiler-builtins/libm/src/math/arch/x86/mod.rs @@ -0,0 +1,8 @@ +//! Architecture-specific support for x86-32 with SSE2 (i686) and x86-64. + +mod detect; +mod fma; +mod sqrt; + +pub use fma::{fma, fmaf}; +pub use sqrt::{sqrt, sqrtf}; diff --git a/library/compiler-builtins/libm/src/math/arch/x86/sqrt.rs b/library/compiler-builtins/libm/src/math/arch/x86/sqrt.rs index 454aa285074d6..d172e1239f1a9 100644 --- a/library/compiler-builtins/libm/src/math/arch/x86/sqrt.rs +++ b/library/compiler-builtins/libm/src/math/arch/x86/sqrt.rs @@ -1,10 +1,3 @@ -//! Architecture-specific support for x86-32 and x86-64 with SSE2 - -mod detect; -mod fma; - -pub use fma::{fma, fmaf}; - pub fn sqrtf(mut x: f32) -> f32 { // SAFETY: `sqrtss` is part of `sse2`, which this module is gated behind. It has no memory // access or side effects. From bf73d7c9fecb1fc651aab174366c4844ed4b30a1 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Mon, 30 Mar 2026 00:23:22 -0500 Subject: [PATCH 048/183] libm: Reorder functions in `arch/` from smallest to largest type Make this module consistent with other areas of code containing multiple types. --- .../libm/src/math/arch/aarch64/rounding.rs | 14 ++++++------- .../libm/src/math/arch/aarch64/sqrt.rs | 20 +++++++++---------- .../libm/src/math/arch/wasm32/rounding.rs | 20 +++++++++---------- 3 files changed, 27 insertions(+), 27 deletions(-) diff --git a/library/compiler-builtins/libm/src/math/arch/aarch64/rounding.rs b/library/compiler-builtins/libm/src/math/arch/aarch64/rounding.rs index 6549497d9cd7d..255e8e85b2f0b 100644 --- a/library/compiler-builtins/libm/src/math/arch/aarch64/rounding.rs +++ b/library/compiler-builtins/libm/src/math/arch/aarch64/rounding.rs @@ -6,14 +6,15 @@ use core::arch::asm; -pub fn rint(mut x: f64) -> f64 { - // SAFETY: `frintn` is available with neon and has no side effects. +#[cfg(all(f16_enabled, target_feature = "fp16"))] +pub fn rintf16(mut x: f16) -> f16 { + // SAFETY: `frintn` is available for `f16` with `fp16` (implies `neon`) and has no side effects. // // `frintn` is always round-to-nearest which does not match the C specification, but Rust does // not support rounding modes. unsafe { asm!( - "frintn {x:d}, {x:d}", + "frintn {x:h}, {x:h}", x = inout(vreg) x, options(nomem, nostack, pure) ); @@ -36,15 +37,14 @@ pub fn rintf(mut x: f32) -> f32 { x } -#[cfg(all(f16_enabled, target_feature = "fp16"))] -pub fn rintf16(mut x: f16) -> f16 { - // SAFETY: `frintn` is available for `f16` with `fp16` (implies `neon`) and has no side effects. +pub fn rint(mut x: f64) -> f64 { + // SAFETY: `frintn` is available with neon and has no side effects. // // `frintn` is always round-to-nearest which does not match the C specification, but Rust does // not support rounding modes. unsafe { asm!( - "frintn {x:h}, {x:h}", + "frintn {x:d}, {x:d}", x = inout(vreg) x, options(nomem, nostack, pure) ); diff --git a/library/compiler-builtins/libm/src/math/arch/aarch64/sqrt.rs b/library/compiler-builtins/libm/src/math/arch/aarch64/sqrt.rs index 8a08ab3292fc2..e3743dfd558aa 100644 --- a/library/compiler-builtins/libm/src/math/arch/aarch64/sqrt.rs +++ b/library/compiler-builtins/libm/src/math/arch/aarch64/sqrt.rs @@ -1,10 +1,12 @@ use core::arch::asm; -pub fn sqrtf(mut x: f32) -> f32 { - // SAFETY: `fsqrt` is available with neon and has no side effects. +#[cfg(all(f16_enabled, target_feature = "fp16"))] +pub fn sqrtf16(mut x: f16) -> f16 { + // SAFETY: `fsqrt` is available for `f16` with `fp16` (implies `neon`) and has no + // side effects. unsafe { asm!( - "fsqrt {x:s}, {x:s}", + "fsqrt {x:h}, {x:h}", x = inout(vreg) x, options(nomem, nostack, pure) ); @@ -12,11 +14,11 @@ pub fn sqrtf(mut x: f32) -> f32 { x } -pub fn sqrt(mut x: f64) -> f64 { +pub fn sqrtf(mut x: f32) -> f32 { // SAFETY: `fsqrt` is available with neon and has no side effects. unsafe { asm!( - "fsqrt {x:d}, {x:d}", + "fsqrt {x:s}, {x:s}", x = inout(vreg) x, options(nomem, nostack, pure) ); @@ -24,13 +26,11 @@ pub fn sqrt(mut x: f64) -> f64 { x } -#[cfg(all(f16_enabled, target_feature = "fp16"))] -pub fn sqrtf16(mut x: f16) -> f16 { - // SAFETY: `fsqrt` is available for `f16` with `fp16` (implies `neon`) and has no - // side effects. +pub fn sqrt(mut x: f64) -> f64 { + // SAFETY: `fsqrt` is available with neon and has no side effects. unsafe { asm!( - "fsqrt {x:h}, {x:h}", + "fsqrt {x:d}, {x:d}", x = inout(vreg) x, options(nomem, nostack, pure) ); diff --git a/library/compiler-builtins/libm/src/math/arch/wasm32/rounding.rs b/library/compiler-builtins/libm/src/math/arch/wasm32/rounding.rs index 35196f0d743cf..1c8914e4561c1 100644 --- a/library/compiler-builtins/libm/src/math/arch/wasm32/rounding.rs +++ b/library/compiler-builtins/libm/src/math/arch/wasm32/rounding.rs @@ -1,34 +1,34 @@ //! Wasm has builtins for simple float operations. Use the unstable `core::arch` intrinsics which //! are significantly faster than soft float operations. -pub fn ceil(x: f64) -> f64 { - core::arch::wasm32::f64_ceil(x) -} - pub fn ceilf(x: f32) -> f32 { core::arch::wasm32::f32_ceil(x) } -pub fn floor(x: f64) -> f64 { - core::arch::wasm32::f64_floor(x) +pub fn ceil(x: f64) -> f64 { + core::arch::wasm32::f64_ceil(x) } pub fn floorf(x: f32) -> f32 { core::arch::wasm32::f32_floor(x) } -pub fn rint(x: f64) -> f64 { - core::arch::wasm32::f64_nearest(x) +pub fn floor(x: f64) -> f64 { + core::arch::wasm32::f64_floor(x) } pub fn rintf(x: f32) -> f32 { core::arch::wasm32::f32_nearest(x) } -pub fn trunc(x: f64) -> f64 { - core::arch::wasm32::f64_trunc(x) +pub fn rint(x: f64) -> f64 { + core::arch::wasm32::f64_nearest(x) } pub fn truncf(x: f32) -> f32 { core::arch::wasm32::f32_trunc(x) } + +pub fn trunc(x: f64) -> f64 { + core::arch::wasm32::f64_trunc(x) +} From b8ee2ff8608837770969836ffebe5588c0f2206b Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Mon, 30 Mar 2026 01:50:08 -0500 Subject: [PATCH 049/183] etc: Search for `*_status` and `*_round` functions Account for function definitions in `generic` that have one of our standard suffixes in the API searcher. --- .../etc/function-definitions.json | 13 +++++++++--- .../compiler-builtins/etc/update-api-list.py | 20 +++++++++++++++---- 2 files changed, 26 insertions(+), 7 deletions(-) diff --git a/library/compiler-builtins/etc/function-definitions.json b/library/compiler-builtins/etc/function-definitions.json index 6792294d538e3..39f7897047798 100644 --- a/library/compiler-builtins/etc/function-definitions.json +++ b/library/compiler-builtins/etc/function-definitions.json @@ -344,7 +344,8 @@ "sources": [ "libm/src/math/arch/aarch64/fma.rs", "libm/src/math/arch/x86/fma.rs", - "libm/src/math/fma.rs" + "libm/src/math/fma.rs", + "libm/src/math/generic/fma.rs" ], "type": "f64" }, @@ -352,13 +353,15 @@ "sources": [ "libm/src/math/arch/aarch64/fma.rs", "libm/src/math/arch/x86/fma.rs", - "libm/src/math/fma.rs" + "libm/src/math/fma.rs", + "libm/src/math/generic/fma.rs" ], "type": "f32" }, "fmaf128": { "sources": [ - "libm/src/math/fma.rs" + "libm/src/math/fma.rs", + "libm/src/math/generic/fma.rs" ], "type": "f128" }, @@ -822,6 +825,7 @@ "sources": [ "libm/src/math/arch/aarch64/rounding.rs", "libm/src/math/arch/wasm32/rounding.rs", + "libm/src/math/generic/rint.rs", "libm/src/math/rint.rs" ], "type": "f64" @@ -830,12 +834,14 @@ "sources": [ "libm/src/math/arch/aarch64/rounding.rs", "libm/src/math/arch/wasm32/rounding.rs", + "libm/src/math/generic/rint.rs", "libm/src/math/rint.rs" ], "type": "f32" }, "rintf128": { "sources": [ + "libm/src/math/generic/rint.rs", "libm/src/math/rint.rs" ], "type": "f128" @@ -843,6 +849,7 @@ "rintf16": { "sources": [ "libm/src/math/arch/aarch64/rounding.rs", + "libm/src/math/generic/rint.rs", "libm/src/math/rint.rs" ], "type": "f16" diff --git a/library/compiler-builtins/etc/update-api-list.py b/library/compiler-builtins/etc/update-api-list.py index 03fc39618590d..f6fad6466255b 100755 --- a/library/compiler-builtins/etc/update-api-list.py +++ b/library/compiler-builtins/etc/update-api-list.py @@ -118,10 +118,20 @@ def _init_function_list(self, index: IndexTy) -> None: def _init_defs(self, index: IndexTy) -> None: defs = {name: set() for name in self.public_functions} - funcs = (i for i in index.values() if "function" in i["inner"]) - funcs = (f for f in funcs if f["name"] in self.public_functions) - for func in funcs: - defs[func["name"]].add(func["span"]["filename"]) + all_funcs = (i for i in index.values() if "function" in i["inner"]) + + for func_def in all_funcs: + func_def_name = func_def["name"] + for pub_func_name in self.public_functions: + needles = [ + pub_func_name, + f"{pub_func_name}_round", + f"{pub_func_name}_status", + ] + if not any(needle == func_def_name for needle in needles): + continue + + defs[pub_func_name].add(func_def["span"]["filename"]) # A lot of the `arch` module is often configured out so doesn't show up in docs. Use # string matching as a fallback. @@ -136,6 +146,8 @@ def _init_defs(self, index: IndexTy) -> None: for name, sources in defs.items(): base_sources = defs[base_name(name)[0]] + + # Also add any functions in `generic` that use this function's base name for src in (s for s in base_sources if "generic" in s): sources.add(src) From 1a5220e61d3ccffd68e1b0499092e1cd40ba98d3 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Mon, 30 Mar 2026 01:37:54 -0500 Subject: [PATCH 050/183] libm: Move tests out of `generic` to the consuming module Make it easier for us to test both the generic and type-specific versions of functions at once. --- .../compiler-builtins/libm/src/math/ceil.rs | 96 ++++++++- .../compiler-builtins/libm/src/math/floor.rs | 96 ++++++++- .../libm/src/math/generic/ceil.rs | 91 --------- .../libm/src/math/generic/floor.rs | 91 --------- .../libm/src/math/generic/mod.rs | 20 +- .../libm/src/math/generic/rint.rs | 85 -------- .../libm/src/math/generic/round.rs | 77 +------- .../libm/src/math/generic/sqrt.rs | 186 ------------------ .../libm/src/math/generic/trunc.rs | 91 --------- .../compiler-builtins/libm/src/math/round.rs | 83 +++++++- .../libm/src/math/roundeven.rs | 97 ++++++++- .../compiler-builtins/libm/src/math/sqrt.rs | 186 +++++++++++++++++- .../compiler-builtins/libm/src/math/trunc.rs | 92 ++++++++- 13 files changed, 636 insertions(+), 655 deletions(-) diff --git a/library/compiler-builtins/libm/src/math/ceil.rs b/library/compiler-builtins/libm/src/math/ceil.rs index 2cac49f29ba97..68da1f59228a5 100644 --- a/library/compiler-builtins/libm/src/math/ceil.rs +++ b/library/compiler-builtins/libm/src/math/ceil.rs @@ -1,10 +1,12 @@ +use super::generic; + /// Ceil (f16) /// /// Finds the nearest integer greater than or equal to `x`. #[cfg(f16_enabled)] #[cfg_attr(assert_no_panic, no_panic::no_panic)] pub fn ceilf16(x: f16) -> f16 { - super::generic::ceil(x) + generic::ceil_status(x).val } /// Ceil (f32) @@ -18,7 +20,7 @@ pub fn ceilf(x: f32) -> f32 { args: x, } - super::generic::ceil(x) + generic::ceil_status(x).val } /// Ceil (f64) @@ -33,7 +35,7 @@ pub fn ceil(x: f64) -> f64 { args: x, } - super::generic::ceil(x) + generic::ceil_status(x).val } /// Ceil (f128) @@ -42,5 +44,91 @@ pub fn ceil(x: f64) -> f64 { #[cfg(f128_enabled)] #[cfg_attr(assert_no_panic, no_panic::no_panic)] pub fn ceilf128(x: f128) -> f128 { - super::generic::ceil(x) + generic::ceil_status(x).val +} + +#[cfg(test)] +mod tests { + use super::*; + use crate::support::{Float, FpResult, Hex, Status}; + + macro_rules! cases { + ($f:ty) => { + [ + // roundtrip + (0.0, 0.0, Status::OK), + (-0.0, -0.0, Status::OK), + (1.0, 1.0, Status::OK), + (-1.0, -1.0, Status::OK), + (<$f>::INFINITY, <$f>::INFINITY, Status::OK), + (<$f>::NEG_INFINITY, <$f>::NEG_INFINITY, Status::OK), + // with rounding + (0.1, 1.0, Status::INEXACT), + (-0.1, -0.0, Status::INEXACT), + (0.5, 1.0, Status::INEXACT), + (-0.5, -0.0, Status::INEXACT), + (0.9, 1.0, Status::INEXACT), + (-0.9, -0.0, Status::INEXACT), + (1.1, 2.0, Status::INEXACT), + (-1.1, -1.0, Status::INEXACT), + (1.5, 2.0, Status::INEXACT), + (-1.5, -1.0, Status::INEXACT), + (1.9, 2.0, Status::INEXACT), + (-1.9, -1.0, Status::INEXACT), + ] + }; + } + + #[track_caller] + fn check(cases: &[(F, F, Status)]) { + for &(x, exp_res, exp_stat) in cases { + let FpResult { val, status } = generic::ceil_status(x); + assert_biteq!(val, exp_res, "{x:?} {}", Hex(x)); + assert_eq!( + status, + exp_stat, + "{x:?} {} -> {exp_res:?} {}", + Hex(x), + Hex(exp_res) + ); + } + } + + #[test] + #[cfg(f16_enabled)] + fn check_f16() { + check::(&cases!(f16)); + check::(&[ + (hf16!("0x1p10"), hf16!("0x1p10"), Status::OK), + (hf16!("-0x1p10"), hf16!("-0x1p10"), Status::OK), + ]); + } + + #[test] + fn check_f32() { + check::(&cases!(f32)); + check::(&[ + (hf32!("0x1p23"), hf32!("0x1p23"), Status::OK), + (hf32!("-0x1p23"), hf32!("-0x1p23"), Status::OK), + ]); + } + + #[test] + fn check_f64() { + check::(&cases!(f64)); + check::(&[ + (hf64!("0x1p52"), hf64!("0x1p52"), Status::OK), + (hf64!("-0x1p52"), hf64!("-0x1p52"), Status::OK), + ]); + } + + #[test] + #[cfg(f128_enabled)] + fn spec_tests_f128() { + check::(&cases!(f128)); + check::(&[ + (hf128!("0x1p112"), hf128!("0x1p112"), Status::OK), + (hf128!("-0x1p112"), hf128!("-0x1p112"), Status::OK), + ]); + } } diff --git a/library/compiler-builtins/libm/src/math/floor.rs b/library/compiler-builtins/libm/src/math/floor.rs index 7241c427f6463..f8bbc4b26ce66 100644 --- a/library/compiler-builtins/libm/src/math/floor.rs +++ b/library/compiler-builtins/libm/src/math/floor.rs @@ -1,10 +1,12 @@ +use super::generic; + /// Floor (f16) /// /// Finds the nearest integer less than or equal to `x`. #[cfg(f16_enabled)] #[cfg_attr(assert_no_panic, no_panic::no_panic)] pub fn floorf16(x: f16) -> f16 { - return super::generic::floor(x); + return generic::floor_status(x).val; } /// Floor (f64) @@ -19,7 +21,7 @@ pub fn floor(x: f64) -> f64 { args: x, } - return super::generic::floor(x); + return generic::floor_status(x).val; } /// Floor (f32) @@ -33,7 +35,7 @@ pub fn floorf(x: f32) -> f32 { args: x, } - return super::generic::floor(x); + return generic::floor_status(x).val; } /// Floor (f128) @@ -42,5 +44,91 @@ pub fn floorf(x: f32) -> f32 { #[cfg(f128_enabled)] #[cfg_attr(assert_no_panic, no_panic::no_panic)] pub fn floorf128(x: f128) -> f128 { - return super::generic::floor(x); + return generic::floor_status(x).val; +} + +#[cfg(test)] +mod tests { + use super::*; + use crate::support::{Float, FpResult, Hex, Status}; + + macro_rules! cases { + ($f:ty) => { + [ + // roundtrip + (0.0, 0.0, Status::OK), + (-0.0, -0.0, Status::OK), + (1.0, 1.0, Status::OK), + (-1.0, -1.0, Status::OK), + (<$f>::INFINITY, <$f>::INFINITY, Status::OK), + (<$f>::NEG_INFINITY, <$f>::NEG_INFINITY, Status::OK), + // with rounding + (0.1, 0.0, Status::INEXACT), + (-0.1, -1.0, Status::INEXACT), + (0.5, 0.0, Status::INEXACT), + (-0.5, -1.0, Status::INEXACT), + (0.9, 0.0, Status::INEXACT), + (-0.9, -1.0, Status::INEXACT), + (1.1, 1.0, Status::INEXACT), + (-1.1, -2.0, Status::INEXACT), + (1.5, 1.0, Status::INEXACT), + (-1.5, -2.0, Status::INEXACT), + (1.9, 1.0, Status::INEXACT), + (-1.9, -2.0, Status::INEXACT), + ] + }; + } + + #[track_caller] + fn check(cases: &[(F, F, Status)]) { + for &(x, exp_res, exp_stat) in cases { + let FpResult { val, status } = generic::floor_status(x); + assert_biteq!(val, exp_res, "{x:?} {}", Hex(x)); + assert_eq!( + status, + exp_stat, + "{x:?} {} -> {exp_res:?} {}", + Hex(x), + Hex(exp_res) + ); + } + } + + #[test] + #[cfg(f16_enabled)] + fn check_f16() { + check::(&cases!(f16)); + check::(&[ + (hf16!("0x1p10"), hf16!("0x1p10"), Status::OK), + (hf16!("-0x1p10"), hf16!("-0x1p10"), Status::OK), + ]); + } + + #[test] + fn check_f32() { + check::(&cases!(f32)); + check::(&[ + (hf32!("0x1p23"), hf32!("0x1p23"), Status::OK), + (hf32!("-0x1p23"), hf32!("-0x1p23"), Status::OK), + ]); + } + + #[test] + fn check_f64() { + check::(&cases!(f64)); + check::(&[ + (hf64!("0x1p52"), hf64!("0x1p52"), Status::OK), + (hf64!("-0x1p52"), hf64!("-0x1p52"), Status::OK), + ]); + } + + #[test] + #[cfg(f128_enabled)] + fn spec_tests_f128() { + check::(&cases!(f128)); + check::(&[ + (hf128!("0x1p112"), hf128!("0x1p112"), Status::OK), + (hf128!("-0x1p112"), hf128!("-0x1p112"), Status::OK), + ]); + } } diff --git a/library/compiler-builtins/libm/src/math/generic/ceil.rs b/library/compiler-builtins/libm/src/math/generic/ceil.rs index 21f1226e92ab4..944cb4d4c7259 100644 --- a/library/compiler-builtins/libm/src/math/generic/ceil.rs +++ b/library/compiler-builtins/libm/src/math/generic/ceil.rs @@ -9,11 +9,6 @@ use crate::support::{Float, FpResult, Int, IntTy, MinInt, Status}; -#[inline] -pub fn ceil(x: F) -> F { - ceil_status(x).val -} - #[inline] pub fn ceil_status(x: F) -> FpResult { let zero = IntTy::::ZERO; @@ -66,89 +61,3 @@ pub fn ceil_status(x: F) -> FpResult { FpResult::new(res, status) } - -#[cfg(test)] -mod tests { - use super::*; - use crate::support::Hex; - - macro_rules! cases { - ($f:ty) => { - [ - // roundtrip - (0.0, 0.0, Status::OK), - (-0.0, -0.0, Status::OK), - (1.0, 1.0, Status::OK), - (-1.0, -1.0, Status::OK), - (<$f>::INFINITY, <$f>::INFINITY, Status::OK), - (<$f>::NEG_INFINITY, <$f>::NEG_INFINITY, Status::OK), - // with rounding - (0.1, 1.0, Status::INEXACT), - (-0.1, -0.0, Status::INEXACT), - (0.5, 1.0, Status::INEXACT), - (-0.5, -0.0, Status::INEXACT), - (0.9, 1.0, Status::INEXACT), - (-0.9, -0.0, Status::INEXACT), - (1.1, 2.0, Status::INEXACT), - (-1.1, -1.0, Status::INEXACT), - (1.5, 2.0, Status::INEXACT), - (-1.5, -1.0, Status::INEXACT), - (1.9, 2.0, Status::INEXACT), - (-1.9, -1.0, Status::INEXACT), - ] - }; - } - - #[track_caller] - fn check(cases: &[(F, F, Status)]) { - for &(x, exp_res, exp_stat) in cases { - let FpResult { val, status } = ceil_status(x); - assert_biteq!(val, exp_res, "{x:?} {}", Hex(x)); - assert_eq!( - status, - exp_stat, - "{x:?} {} -> {exp_res:?} {}", - Hex(x), - Hex(exp_res) - ); - } - } - - #[test] - #[cfg(f16_enabled)] - fn check_f16() { - check::(&cases!(f16)); - check::(&[ - (hf16!("0x1p10"), hf16!("0x1p10"), Status::OK), - (hf16!("-0x1p10"), hf16!("-0x1p10"), Status::OK), - ]); - } - - #[test] - fn check_f32() { - check::(&cases!(f32)); - check::(&[ - (hf32!("0x1p23"), hf32!("0x1p23"), Status::OK), - (hf32!("-0x1p23"), hf32!("-0x1p23"), Status::OK), - ]); - } - - #[test] - fn check_f64() { - check::(&cases!(f64)); - check::(&[ - (hf64!("0x1p52"), hf64!("0x1p52"), Status::OK), - (hf64!("-0x1p52"), hf64!("-0x1p52"), Status::OK), - ]); - } - - #[test] - #[cfg(f128_enabled)] - fn spec_tests_f128() { - check::(&cases!(f128)); - check::(&[ - (hf128!("0x1p112"), hf128!("0x1p112"), Status::OK), - (hf128!("-0x1p112"), hf128!("-0x1p112"), Status::OK), - ]); - } -} diff --git a/library/compiler-builtins/libm/src/math/generic/floor.rs b/library/compiler-builtins/libm/src/math/generic/floor.rs index ce0934f7adc4f..a99d192831e3c 100644 --- a/library/compiler-builtins/libm/src/math/generic/floor.rs +++ b/library/compiler-builtins/libm/src/math/generic/floor.rs @@ -9,11 +9,6 @@ use crate::support::{Float, FpResult, Int, IntTy, MinInt, Status}; -#[inline] -pub fn floor(x: F) -> F { - floor_status(x).val -} - #[inline] pub fn floor_status(x: F) -> FpResult { let zero = IntTy::::ZERO; @@ -58,89 +53,3 @@ pub fn floor_status(x: F) -> FpResult { FpResult::new(res, Status::INEXACT) } - -#[cfg(test)] -mod tests { - use super::*; - use crate::support::Hex; - - macro_rules! cases { - ($f:ty) => { - [ - // roundtrip - (0.0, 0.0, Status::OK), - (-0.0, -0.0, Status::OK), - (1.0, 1.0, Status::OK), - (-1.0, -1.0, Status::OK), - (<$f>::INFINITY, <$f>::INFINITY, Status::OK), - (<$f>::NEG_INFINITY, <$f>::NEG_INFINITY, Status::OK), - // with rounding - (0.1, 0.0, Status::INEXACT), - (-0.1, -1.0, Status::INEXACT), - (0.5, 0.0, Status::INEXACT), - (-0.5, -1.0, Status::INEXACT), - (0.9, 0.0, Status::INEXACT), - (-0.9, -1.0, Status::INEXACT), - (1.1, 1.0, Status::INEXACT), - (-1.1, -2.0, Status::INEXACT), - (1.5, 1.0, Status::INEXACT), - (-1.5, -2.0, Status::INEXACT), - (1.9, 1.0, Status::INEXACT), - (-1.9, -2.0, Status::INEXACT), - ] - }; - } - - #[track_caller] - fn check(cases: &[(F, F, Status)]) { - for &(x, exp_res, exp_stat) in cases { - let FpResult { val, status } = floor_status(x); - assert_biteq!(val, exp_res, "{x:?} {}", Hex(x)); - assert_eq!( - status, - exp_stat, - "{x:?} {} -> {exp_res:?} {}", - Hex(x), - Hex(exp_res) - ); - } - } - - #[test] - #[cfg(f16_enabled)] - fn check_f16() { - check::(&cases!(f16)); - check::(&[ - (hf16!("0x1p10"), hf16!("0x1p10"), Status::OK), - (hf16!("-0x1p10"), hf16!("-0x1p10"), Status::OK), - ]); - } - - #[test] - fn check_f32() { - check::(&cases!(f32)); - check::(&[ - (hf32!("0x1p23"), hf32!("0x1p23"), Status::OK), - (hf32!("-0x1p23"), hf32!("-0x1p23"), Status::OK), - ]); - } - - #[test] - fn check_f64() { - check::(&cases!(f64)); - check::(&[ - (hf64!("0x1p52"), hf64!("0x1p52"), Status::OK), - (hf64!("-0x1p52"), hf64!("-0x1p52"), Status::OK), - ]); - } - - #[test] - #[cfg(f128_enabled)] - fn spec_tests_f128() { - check::(&cases!(f128)); - check::(&[ - (hf128!("0x1p112"), hf128!("0x1p112"), Status::OK), - (hf128!("-0x1p112"), hf128!("-0x1p112"), Status::OK), - ]); - } -} diff --git a/library/compiler-builtins/libm/src/math/generic/mod.rs b/library/compiler-builtins/libm/src/math/generic/mod.rs index 114fcddf516e5..b54e0a15fecf2 100644 --- a/library/compiler-builtins/libm/src/math/generic/mod.rs +++ b/library/compiler-builtins/libm/src/math/generic/mod.rs @@ -1,5 +1,11 @@ -// Note: generic functions are marked `#[inline]` because, even though generic functions are -// typically inlined, this does not seem to always be the case. +//! Generic implementations that are shared by multiple types. +//! +//! Implementation and usage notes: +//! +//! * Generic functions are marked `#[inline]` because, even though generic functions are +//! typically inlined, we seem to occasionally run into exceptions. +//! * Tests usually live wherever the functions are consumed (e.g. `src/ceil`) so they can be +//! reused to test arch-specific implementations. mod ceil; mod copysign; @@ -23,11 +29,11 @@ mod scalbn; mod sqrt; mod trunc; -pub use ceil::ceil; +pub use ceil::ceil_status; pub use copysign::copysign; pub use fabs::fabs; pub use fdim::fdim; -pub use floor::floor; +pub use floor::floor_status; pub use fma::fma_round; pub use fma_wide::fma_wide_round; pub use fmax::fmax; @@ -42,5 +48,7 @@ pub use ilogb::ilogb; pub use rint::rint_round; pub use round::round; pub use scalbn::scalbn; -pub use sqrt::sqrt; -pub use trunc::trunc; +#[cfg(test)] +pub use sqrt::SqrtHelper; +pub use sqrt::sqrt_round; +pub use trunc::trunc_status; diff --git a/library/compiler-builtins/libm/src/math/generic/rint.rs b/library/compiler-builtins/libm/src/math/generic/rint.rs index 94bef770e4d2f..76f625f3376e1 100644 --- a/library/compiler-builtins/libm/src/math/generic/rint.rs +++ b/library/compiler-builtins/libm/src/math/generic/rint.rs @@ -43,88 +43,3 @@ pub fn rint_round(x: F, _round: Round) -> FpResult { FpResult::ok(res) } - -#[cfg(test)] -mod tests { - use super::*; - use crate::support::{Hex, Status}; - - fn spec_test(cases: &[(F, F, Status)]) { - let roundtrip = [ - F::ZERO, - F::ONE, - F::NEG_ONE, - F::NEG_ZERO, - F::INFINITY, - F::NEG_INFINITY, - ]; - - for x in roundtrip { - let FpResult { val, status } = rint_round(x, Round::Nearest); - assert_biteq!(val, x, "rint_round({})", Hex(x)); - assert_eq!(status, Status::OK, "{}", Hex(x)); - } - - for &(x, res, res_stat) in cases { - let FpResult { val, status } = rint_round(x, Round::Nearest); - assert_biteq!(val, res, "rint_round({})", Hex(x)); - assert_eq!(status, res_stat, "{}", Hex(x)); - } - } - - #[test] - #[cfg(f16_enabled)] - fn spec_tests_f16() { - let cases = []; - spec_test::(&cases); - } - - #[test] - fn spec_tests_f32() { - let cases = [ - (0.1, 0.0, Status::OK), - (-0.1, -0.0, Status::OK), - (0.5, 0.0, Status::OK), - (-0.5, -0.0, Status::OK), - (0.9, 1.0, Status::OK), - (-0.9, -1.0, Status::OK), - (1.1, 1.0, Status::OK), - (-1.1, -1.0, Status::OK), - (1.5, 2.0, Status::OK), - (-1.5, -2.0, Status::OK), - (1.9, 2.0, Status::OK), - (-1.9, -2.0, Status::OK), - (2.8, 3.0, Status::OK), - (-2.8, -3.0, Status::OK), - ]; - spec_test::(&cases); - } - - #[test] - fn spec_tests_f64() { - let cases = [ - (0.1, 0.0, Status::OK), - (-0.1, -0.0, Status::OK), - (0.5, 0.0, Status::OK), - (-0.5, -0.0, Status::OK), - (0.9, 1.0, Status::OK), - (-0.9, -1.0, Status::OK), - (1.1, 1.0, Status::OK), - (-1.1, -1.0, Status::OK), - (1.5, 2.0, Status::OK), - (-1.5, -2.0, Status::OK), - (1.9, 2.0, Status::OK), - (-1.9, -2.0, Status::OK), - (2.8, 3.0, Status::OK), - (-2.8, -3.0, Status::OK), - ]; - spec_test::(&cases); - } - - #[test] - #[cfg(f128_enabled)] - fn spec_tests_f128() { - let cases = []; - spec_test::(&cases); - } -} diff --git a/library/compiler-builtins/libm/src/math/generic/round.rs b/library/compiler-builtins/libm/src/math/generic/round.rs index 16739f01d8775..9cab1e22c2c6c 100644 --- a/library/compiler-builtins/libm/src/math/generic/round.rs +++ b/library/compiler-builtins/libm/src/math/generic/round.rs @@ -1,4 +1,4 @@ -use super::{copysign, trunc}; +use super::{copysign, trunc_status}; use crate::support::{Float, MinInt}; #[inline] @@ -6,78 +6,5 @@ pub fn round(x: F) -> F { let f0p5 = F::from_parts(false, F::EXP_BIAS - 1, F::Int::ZERO); // 0.5 let f0p25 = F::from_parts(false, F::EXP_BIAS - 2, F::Int::ZERO); // 0.25 - trunc(x + copysign(f0p5 - f0p25 * F::EPSILON, x)) -} - -#[cfg(test)] -mod tests { - use super::*; - - #[test] - #[cfg(f16_enabled)] - fn zeroes_f16() { - assert_biteq!(round(0.0_f16), 0.0_f16); - assert_biteq!(round(-0.0_f16), -0.0_f16); - } - - #[test] - #[cfg(f16_enabled)] - fn sanity_check_f16() { - assert_eq!(round(-1.0_f16), -1.0); - assert_eq!(round(2.8_f16), 3.0); - assert_eq!(round(-0.5_f16), -1.0); - assert_eq!(round(0.5_f16), 1.0); - assert_eq!(round(-1.5_f16), -2.0); - assert_eq!(round(1.5_f16), 2.0); - } - - #[test] - fn zeroes_f32() { - assert_biteq!(round(0.0_f32), 0.0_f32); - assert_biteq!(round(-0.0_f32), -0.0_f32); - } - - #[test] - fn sanity_check_f32() { - assert_eq!(round(-1.0_f32), -1.0); - assert_eq!(round(2.8_f32), 3.0); - assert_eq!(round(-0.5_f32), -1.0); - assert_eq!(round(0.5_f32), 1.0); - assert_eq!(round(-1.5_f32), -2.0); - assert_eq!(round(1.5_f32), 2.0); - } - - #[test] - fn zeroes_f64() { - assert_biteq!(round(0.0_f64), 0.0_f64); - assert_biteq!(round(-0.0_f64), -0.0_f64); - } - - #[test] - fn sanity_check_f64() { - assert_eq!(round(-1.0_f64), -1.0); - assert_eq!(round(2.8_f64), 3.0); - assert_eq!(round(-0.5_f64), -1.0); - assert_eq!(round(0.5_f64), 1.0); - assert_eq!(round(-1.5_f64), -2.0); - assert_eq!(round(1.5_f64), 2.0); - } - - #[test] - #[cfg(f128_enabled)] - fn zeroes_f128() { - assert_biteq!(round(0.0_f128), 0.0_f128); - assert_biteq!(round(-0.0_f128), -0.0_f128); - } - - #[test] - #[cfg(f128_enabled)] - fn sanity_check_f128() { - assert_eq!(round(-1.0_f128), -1.0); - assert_eq!(round(2.8_f128), 3.0); - assert_eq!(round(-0.5_f128), -1.0); - assert_eq!(round(0.5_f128), 1.0); - assert_eq!(round(-1.5_f128), -2.0); - assert_eq!(round(1.5_f128), 2.0); - } + trunc_status(x + copysign(f0p5 - f0p25 * F::EPSILON, x)).val } diff --git a/library/compiler-builtins/libm/src/math/generic/sqrt.rs b/library/compiler-builtins/libm/src/math/generic/sqrt.rs index e97a43d349569..0a0d35a8a6226 100644 --- a/library/compiler-builtins/libm/src/math/generic/sqrt.rs +++ b/library/compiler-builtins/libm/src/math/generic/sqrt.rs @@ -45,20 +45,6 @@ use crate::support::{ CastFrom, CastInto, DInt, Float, FpResult, HInt, Int, IntTy, MinInt, Round, Status, cold_path, }; -#[inline] -pub fn sqrt(x: F) -> F -where - F: Float + SqrtHelper, - F::Int: HInt, - F::Int: From, - F::Int: From, - F::Int: CastInto, - F::Int: CastInto, - u32: CastInto, -{ - sqrt_round(x, Round::Nearest).val -} - #[inline] pub fn sqrt_round(x: F, _round: Round) -> FpResult where @@ -365,175 +351,3 @@ static RSQRT_TAB: [u16; 128] = [ 0xc116, 0xc03c, 0xbf65, 0xbe90, 0xbdbe, 0xbcef, 0xbc23, 0xbb59, 0xba91, 0xb9cc, 0xb90a, 0xb84a, 0xb78c, 0xb6d0, 0xb617, 0xb560, ]; - -#[cfg(test)] -mod tests { - use super::*; - - /// Test behavior specified in IEEE 754 `squareRoot`. - fn spec_test() - where - F: Float + SqrtHelper, - F::Int: HInt, - F::Int: From, - F::Int: From, - F::Int: CastInto, - F::Int: CastInto, - u32: CastInto, - { - // Values that should return a NaN and raise invalid - let nan = [F::NEG_INFINITY, F::NEG_ONE, F::NAN, F::MIN]; - - // Values that return unaltered - let roundtrip = [F::ZERO, F::NEG_ZERO, F::INFINITY]; - - for x in nan { - let FpResult { val, status } = sqrt_round(x, Round::Nearest); - assert!(val.is_nan()); - assert!(status == Status::INVALID); - } - - for x in roundtrip { - let FpResult { val, status } = sqrt_round(x, Round::Nearest); - assert_biteq!(val, x); - assert!(status == Status::OK); - } - } - - #[test] - #[cfg(f16_enabled)] - fn sanity_check_f16() { - assert_biteq!(sqrt(100.0f16), 10.0); - assert_biteq!(sqrt(4.0f16), 2.0); - } - - #[test] - #[cfg(f16_enabled)] - fn spec_tests_f16() { - spec_test::(); - } - - #[test] - #[cfg(f16_enabled)] - #[allow(clippy::approx_constant)] - fn conformance_tests_f16() { - let cases = [ - (f16::PI, 0x3f17_u16), - (10000.0_f16, 0x5640_u16), - (f16::from_bits(0x0000000f), 0x13bf_u16), - (f16::INFINITY, f16::INFINITY.to_bits()), - ]; - - for (input, output) in cases { - assert_biteq!( - sqrt(input), - f16::from_bits(output), - "input: {input:?} ({:#018x})", - input.to_bits() - ); - } - } - - #[test] - fn sanity_check_f32() { - assert_biteq!(sqrt(100.0f32), 10.0); - assert_biteq!(sqrt(4.0f32), 2.0); - } - - #[test] - fn spec_tests_f32() { - spec_test::(); - } - - #[test] - #[allow(clippy::approx_constant)] - fn conformance_tests_f32() { - let cases = [ - (f32::PI, 0x3fe2dfc5_u32), - (10000.0f32, 0x42c80000_u32), - (f32::from_bits(0x0000000f), 0x1b2f456f_u32), - (f32::INFINITY, f32::INFINITY.to_bits()), - ]; - - for (input, output) in cases { - assert_biteq!( - sqrt(input), - f32::from_bits(output), - "input: {input:?} ({:#018x})", - input.to_bits() - ); - } - } - - #[test] - fn sanity_check_f64() { - assert_biteq!(sqrt(100.0f64), 10.0); - assert_biteq!(sqrt(4.0f64), 2.0); - } - - #[test] - fn spec_tests_f64() { - spec_test::(); - } - - #[test] - #[allow(clippy::approx_constant)] - fn conformance_tests_f64() { - let cases = [ - (f64::PI, 0x3ffc5bf891b4ef6a_u64), - (10000.0, 0x4059000000000000_u64), - (f64::from_bits(0x0000000f), 0x1e7efbdeb14f4eda_u64), - (f64::INFINITY, f64::INFINITY.to_bits()), - ]; - - for (input, output) in cases { - assert_biteq!( - sqrt(input), - f64::from_bits(output), - "input: {input:?} ({:#018x})", - input.to_bits() - ); - } - } - - #[test] - #[cfg(f128_enabled)] - fn sanity_check_f128() { - assert_biteq!(sqrt(100.0f128), 10.0); - assert_biteq!(sqrt(4.0f128), 2.0); - } - - #[test] - #[cfg(f128_enabled)] - fn spec_tests_f128() { - spec_test::(); - } - - #[test] - #[cfg(f128_enabled)] - #[allow(clippy::approx_constant)] - fn conformance_tests_f128() { - let cases = [ - (f128::PI, 0x3fffc5bf891b4ef6aa79c3b0520d5db9_u128), - // 10_000.0, see `f16` for reasoning. - ( - f128::from_bits(0x400c3880000000000000000000000000), - 0x40059000000000000000000000000000_u128, - ), - ( - f128::from_bits(0x0000000f), - 0x1fc9efbdeb14f4ed9b17ae807907e1e9_u128, - ), - (f128::INFINITY, f128::INFINITY.to_bits()), - ]; - - for (input, output) in cases { - assert_biteq!( - sqrt(input), - f128::from_bits(output), - "input: {input:?} ({:#018x})", - input.to_bits() - ); - } - } -} diff --git a/library/compiler-builtins/libm/src/math/generic/trunc.rs b/library/compiler-builtins/libm/src/math/generic/trunc.rs index a1c295f1354ee..0b252fab94ae1 100644 --- a/library/compiler-builtins/libm/src/math/generic/trunc.rs +++ b/library/compiler-builtins/libm/src/math/generic/trunc.rs @@ -3,11 +3,6 @@ use crate::support::{Float, FpResult, Int, IntTy, MinInt, Status}; -#[inline] -pub fn trunc(x: F) -> F { - trunc_status(x).val -} - #[inline] pub fn trunc_status(x: F) -> FpResult { let xi: F::Int = x.to_bits(); @@ -39,89 +34,3 @@ pub fn trunc_status(x: F) -> FpResult { // Now zero the bits we need to truncate and return. FpResult::new(F::from_bits(xi ^ cleared), status) } - -#[cfg(test)] -mod tests { - use super::*; - use crate::support::Hex; - - macro_rules! cases { - ($f:ty) => { - [ - // roundtrip - (0.0, 0.0, Status::OK), - (-0.0, -0.0, Status::OK), - (1.0, 1.0, Status::OK), - (-1.0, -1.0, Status::OK), - (<$f>::INFINITY, <$f>::INFINITY, Status::OK), - (<$f>::NEG_INFINITY, <$f>::NEG_INFINITY, Status::OK), - // with rounding - (0.1, 0.0, Status::INEXACT), - (-0.1, -0.0, Status::INEXACT), - (0.5, 0.0, Status::INEXACT), - (-0.5, -0.0, Status::INEXACT), - (0.9, 0.0, Status::INEXACT), - (-0.9, -0.0, Status::INEXACT), - (1.1, 1.0, Status::INEXACT), - (-1.1, -1.0, Status::INEXACT), - (1.5, 1.0, Status::INEXACT), - (-1.5, -1.0, Status::INEXACT), - (1.9, 1.0, Status::INEXACT), - (-1.9, -1.0, Status::INEXACT), - ] - }; - } - - #[track_caller] - fn check(cases: &[(F, F, Status)]) { - for &(x, exp_res, exp_stat) in cases { - let FpResult { val, status } = trunc_status(x); - assert_biteq!(val, exp_res, "{x:?} {}", Hex(x)); - assert_eq!( - status, - exp_stat, - "{x:?} {} -> {exp_res:?} {}", - Hex(x), - Hex(exp_res) - ); - } - } - - #[test] - #[cfg(f16_enabled)] - fn check_f16() { - check::(&cases!(f16)); - check::(&[ - (hf16!("0x1p10"), hf16!("0x1p10"), Status::OK), - (hf16!("-0x1p10"), hf16!("-0x1p10"), Status::OK), - ]); - } - - #[test] - fn check_f32() { - check::(&cases!(f32)); - check::(&[ - (hf32!("0x1p23"), hf32!("0x1p23"), Status::OK), - (hf32!("-0x1p23"), hf32!("-0x1p23"), Status::OK), - ]); - } - - #[test] - fn check_f64() { - check::(&cases!(f64)); - check::(&[ - (hf64!("0x1p52"), hf64!("0x1p52"), Status::OK), - (hf64!("-0x1p52"), hf64!("-0x1p52"), Status::OK), - ]); - } - - #[test] - #[cfg(f128_enabled)] - fn spec_tests_f128() { - check::(&cases!(f128)); - check::(&[ - (hf128!("0x1p112"), hf128!("0x1p112"), Status::OK), - (hf128!("-0x1p112"), hf128!("-0x1p112"), Status::OK), - ]); - } -} diff --git a/library/compiler-builtins/libm/src/math/round.rs b/library/compiler-builtins/libm/src/math/round.rs index 256197e6ccbee..204ffaf413f67 100644 --- a/library/compiler-builtins/libm/src/math/round.rs +++ b/library/compiler-builtins/libm/src/math/round.rs @@ -1,25 +1,100 @@ +use super::generic; + /// Round `x` to the nearest integer, breaking ties away from zero. #[cfg(f16_enabled)] #[cfg_attr(assert_no_panic, no_panic::no_panic)] pub fn roundf16(x: f16) -> f16 { - super::generic::round(x) + generic::round(x) } /// Round `x` to the nearest integer, breaking ties away from zero. #[cfg_attr(assert_no_panic, no_panic::no_panic)] pub fn roundf(x: f32) -> f32 { - super::generic::round(x) + generic::round(x) } /// Round `x` to the nearest integer, breaking ties away from zero. #[cfg_attr(assert_no_panic, no_panic::no_panic)] pub fn round(x: f64) -> f64 { - super::generic::round(x) + generic::round(x) } /// Round `x` to the nearest integer, breaking ties away from zero. #[cfg(f128_enabled)] #[cfg_attr(assert_no_panic, no_panic::no_panic)] pub fn roundf128(x: f128) -> f128 { - super::generic::round(x) + generic::round(x) +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + #[cfg(f16_enabled)] + fn zeroes_f16() { + assert_biteq!(generic::round(0.0_f16), 0.0_f16); + assert_biteq!(generic::round(-0.0_f16), -0.0_f16); + } + + #[test] + #[cfg(f16_enabled)] + fn sanity_check_f16() { + assert_eq!(generic::round(-1.0_f16), -1.0); + assert_eq!(generic::round(2.8_f16), 3.0); + assert_eq!(generic::round(-0.5_f16), -1.0); + assert_eq!(generic::round(0.5_f16), 1.0); + assert_eq!(generic::round(-1.5_f16), -2.0); + assert_eq!(generic::round(1.5_f16), 2.0); + } + + #[test] + fn zeroes_f32() { + assert_biteq!(generic::round(0.0_f32), 0.0_f32); + assert_biteq!(generic::round(-0.0_f32), -0.0_f32); + } + + #[test] + fn sanity_check_f32() { + assert_eq!(generic::round(-1.0_f32), -1.0); + assert_eq!(generic::round(2.8_f32), 3.0); + assert_eq!(generic::round(-0.5_f32), -1.0); + assert_eq!(generic::round(0.5_f32), 1.0); + assert_eq!(generic::round(-1.5_f32), -2.0); + assert_eq!(generic::round(1.5_f32), 2.0); + } + + #[test] + fn zeroes_f64() { + assert_biteq!(generic::round(0.0_f64), 0.0_f64); + assert_biteq!(generic::round(-0.0_f64), -0.0_f64); + } + + #[test] + fn sanity_check_f64() { + assert_eq!(generic::round(-1.0_f64), -1.0); + assert_eq!(generic::round(2.8_f64), 3.0); + assert_eq!(generic::round(-0.5_f64), -1.0); + assert_eq!(generic::round(0.5_f64), 1.0); + assert_eq!(generic::round(-1.5_f64), -2.0); + assert_eq!(generic::round(1.5_f64), 2.0); + } + + #[test] + #[cfg(f128_enabled)] + fn zeroes_f128() { + assert_biteq!(generic::round(0.0_f128), 0.0_f128); + assert_biteq!(generic::round(-0.0_f128), -0.0_f128); + } + + #[test] + #[cfg(f128_enabled)] + fn sanity_check_f128() { + assert_eq!(generic::round(-1.0_f128), -1.0); + assert_eq!(generic::round(2.8_f128), 3.0); + assert_eq!(generic::round(-0.5_f128), -1.0); + assert_eq!(generic::round(0.5_f128), 1.0); + assert_eq!(generic::round(-1.5_f128), -2.0); + assert_eq!(generic::round(1.5_f128), 2.0); + } } diff --git a/library/compiler-builtins/libm/src/math/roundeven.rs b/library/compiler-builtins/libm/src/math/roundeven.rs index f0d67d41076ec..ec47c8074efa9 100644 --- a/library/compiler-builtins/libm/src/math/roundeven.rs +++ b/library/compiler-builtins/libm/src/math/roundeven.rs @@ -1,25 +1,26 @@ -use super::support::{Float, Round}; +use super::generic; +use super::support::Round; /// Round `x` to the nearest integer, breaking ties toward even. This is IEEE 754 /// `roundToIntegralTiesToEven`. #[cfg(f16_enabled)] #[cfg_attr(assert_no_panic, no_panic::no_panic)] pub fn roundevenf16(x: f16) -> f16 { - roundeven_impl(x) + generic::rint_round(x, Round::Nearest).val } /// Round `x` to the nearest integer, breaking ties toward even. This is IEEE 754 /// `roundToIntegralTiesToEven`. #[cfg_attr(assert_no_panic, no_panic::no_panic)] pub fn roundevenf(x: f32) -> f32 { - roundeven_impl(x) + generic::rint_round(x, Round::Nearest).val } /// Round `x` to the nearest integer, breaking ties toward even. This is IEEE 754 /// `roundToIntegralTiesToEven`. #[cfg_attr(assert_no_panic, no_panic::no_panic)] pub fn roundeven(x: f64) -> f64 { - roundeven_impl(x) + generic::rint_round(x, Round::Nearest).val } /// Round `x` to the nearest integer, breaking ties toward even. This is IEEE 754 @@ -27,10 +28,90 @@ pub fn roundeven(x: f64) -> f64 { #[cfg(f128_enabled)] #[cfg_attr(assert_no_panic, no_panic::no_panic)] pub fn roundevenf128(x: f128) -> f128 { - roundeven_impl(x) + generic::rint_round(x, Round::Nearest).val } -#[inline] -pub fn roundeven_impl(x: F) -> F { - super::generic::rint_round(x, Round::Nearest).val +#[cfg(test)] +mod tests { + use super::*; + use crate::support::{Float, FpResult, Hex, Status}; + + fn spec_test(cases: &[(F, F, Status)]) { + let roundtrip = [ + F::ZERO, + F::ONE, + F::NEG_ONE, + F::NEG_ZERO, + F::INFINITY, + F::NEG_INFINITY, + ]; + + for x in roundtrip { + let FpResult { val, status } = generic::rint_round(x, Round::Nearest); + assert_biteq!(val, x, "rint_round({})", Hex(x)); + assert_eq!(status, Status::OK, "{}", Hex(x)); + } + + for &(x, res, res_stat) in cases { + let FpResult { val, status } = generic::rint_round(x, Round::Nearest); + assert_biteq!(val, res, "rint_round({})", Hex(x)); + assert_eq!(status, res_stat, "{}", Hex(x)); + } + } + + #[test] + #[cfg(f16_enabled)] + fn spec_tests_f16() { + let cases = []; + spec_test::(&cases); + } + + #[test] + fn spec_tests_f32() { + let cases = [ + (0.1, 0.0, Status::OK), + (-0.1, -0.0, Status::OK), + (0.5, 0.0, Status::OK), + (-0.5, -0.0, Status::OK), + (0.9, 1.0, Status::OK), + (-0.9, -1.0, Status::OK), + (1.1, 1.0, Status::OK), + (-1.1, -1.0, Status::OK), + (1.5, 2.0, Status::OK), + (-1.5, -2.0, Status::OK), + (1.9, 2.0, Status::OK), + (-1.9, -2.0, Status::OK), + (2.8, 3.0, Status::OK), + (-2.8, -3.0, Status::OK), + ]; + spec_test::(&cases); + } + + #[test] + fn spec_tests_f64() { + let cases = [ + (0.1, 0.0, Status::OK), + (-0.1, -0.0, Status::OK), + (0.5, 0.0, Status::OK), + (-0.5, -0.0, Status::OK), + (0.9, 1.0, Status::OK), + (-0.9, -1.0, Status::OK), + (1.1, 1.0, Status::OK), + (-1.1, -1.0, Status::OK), + (1.5, 2.0, Status::OK), + (-1.5, -2.0, Status::OK), + (1.9, 2.0, Status::OK), + (-1.9, -2.0, Status::OK), + (2.8, 3.0, Status::OK), + (-2.8, -3.0, Status::OK), + ]; + spec_test::(&cases); + } + + #[test] + #[cfg(f128_enabled)] + fn spec_tests_f128() { + let cases = []; + spec_test::(&cases); + } } diff --git a/library/compiler-builtins/libm/src/math/sqrt.rs b/library/compiler-builtins/libm/src/math/sqrt.rs index 7ba1bc9b32b23..10edf397a0a0a 100644 --- a/library/compiler-builtins/libm/src/math/sqrt.rs +++ b/library/compiler-builtins/libm/src/math/sqrt.rs @@ -1,3 +1,6 @@ +use super::generic; +use crate::support::Round; + /// The square root of `x` (f16). #[cfg(f16_enabled)] #[cfg_attr(assert_no_panic, no_panic::no_panic)] @@ -8,7 +11,7 @@ pub fn sqrtf16(x: f16) -> f16 { args: x, } - return super::generic::sqrt(x); + return generic::sqrt_round(x, Round::Nearest).val; } /// The square root of `x` (f32). @@ -24,7 +27,7 @@ pub fn sqrtf(x: f32) -> f32 { args: x, } - super::generic::sqrt(x) + generic::sqrt_round(x, Round::Nearest).val } /// The square root of `x` (f64). @@ -40,12 +43,187 @@ pub fn sqrt(x: f64) -> f64 { args: x, } - super::generic::sqrt(x) + generic::sqrt_round(x, Round::Nearest).val } /// The square root of `x` (f128). #[cfg(f128_enabled)] #[cfg_attr(assert_no_panic, no_panic::no_panic)] pub fn sqrtf128(x: f128) -> f128 { - return super::generic::sqrt(x); + return generic::sqrt_round(x, Round::Nearest).val; +} + +#[cfg(test)] +mod tests { + use generic::SqrtHelper; + + use super::*; + use crate::support::{CastInto, Float, FpResult, HInt, Status}; + + /// Test behavior specified in IEEE 754 `squareRoot`. + fn spec_test() + where + F: Float + SqrtHelper, + F::Int: HInt, + F::Int: From, + F::Int: From, + F::Int: CastInto, + F::Int: CastInto, + u32: CastInto, + { + // Values that should return a NaN and raise invalid + let nan = [F::NEG_INFINITY, F::NEG_ONE, F::NAN, F::MIN]; + + // Values that return unaltered + let roundtrip = [F::ZERO, F::NEG_ZERO, F::INFINITY]; + + for x in nan { + let FpResult { val, status } = generic::sqrt_round(x, Round::Nearest); + assert!(val.is_nan()); + assert!(status == Status::INVALID); + } + + for x in roundtrip { + let FpResult { val, status } = generic::sqrt_round(x, Round::Nearest); + assert_biteq!(val, x); + assert!(status == Status::OK); + } + } + + #[test] + #[cfg(f16_enabled)] + fn sanity_check_f16() { + assert_biteq!(sqrtf16(100.0f16), 10.0); + assert_biteq!(sqrtf16(4.0f16), 2.0); + } + + #[test] + #[cfg(f16_enabled)] + fn spec_tests_f16() { + spec_test::(); + } + + #[test] + #[cfg(f16_enabled)] + #[allow(clippy::approx_constant)] + fn conformance_tests_f16() { + let cases = [ + (f16::PI, 0x3f17_u16), + (10000.0_f16, 0x5640_u16), + (f16::from_bits(0x0000000f), 0x13bf_u16), + (f16::INFINITY, f16::INFINITY.to_bits()), + ]; + + for (input, output) in cases { + assert_biteq!( + sqrtf16(input), + f16::from_bits(output), + "input: {input:?} ({:#018x})", + input.to_bits() + ); + } + } + + #[test] + fn sanity_check_f32() { + assert_biteq!(sqrtf(100.0f32), 10.0); + assert_biteq!(sqrtf(4.0f32), 2.0); + } + + #[test] + fn spec_tests_f32() { + spec_test::(); + } + + #[test] + #[allow(clippy::approx_constant)] + fn conformance_tests_f32() { + let cases = [ + (f32::PI, 0x3fe2dfc5_u32), + (10000.0f32, 0x42c80000_u32), + (f32::from_bits(0x0000000f), 0x1b2f456f_u32), + (f32::INFINITY, f32::INFINITY.to_bits()), + ]; + + for (input, output) in cases { + assert_biteq!( + sqrtf(input), + f32::from_bits(output), + "input: {input:?} ({:#018x})", + input.to_bits() + ); + } + } + + #[test] + fn sanity_check_f64() { + assert_biteq!(sqrt(100.0f64), 10.0); + assert_biteq!(sqrt(4.0f64), 2.0); + } + + #[test] + fn spec_tests_f64() { + spec_test::(); + } + + #[test] + #[allow(clippy::approx_constant)] + fn conformance_tests_f64() { + let cases = [ + (f64::PI, 0x3ffc5bf891b4ef6a_u64), + (10000.0, 0x4059000000000000_u64), + (f64::from_bits(0x0000000f), 0x1e7efbdeb14f4eda_u64), + (f64::INFINITY, f64::INFINITY.to_bits()), + ]; + + for (input, output) in cases { + assert_biteq!( + sqrt(input), + f64::from_bits(output), + "input: {input:?} ({:#018x})", + input.to_bits() + ); + } + } + + #[test] + #[cfg(f128_enabled)] + fn sanity_check_f128() { + assert_biteq!(sqrtf128(100.0f128), 10.0); + assert_biteq!(sqrtf128(4.0f128), 2.0); + } + + #[test] + #[cfg(f128_enabled)] + fn spec_tests_f128() { + spec_test::(); + } + + #[test] + #[cfg(f128_enabled)] + #[allow(clippy::approx_constant)] + fn conformance_tests_f128() { + let cases = [ + (f128::PI, 0x3fffc5bf891b4ef6aa79c3b0520d5db9_u128), + // 10_000.0, see `f16` for reasoning. + ( + f128::from_bits(0x400c3880000000000000000000000000), + 0x40059000000000000000000000000000_u128, + ), + ( + f128::from_bits(0x0000000f), + 0x1fc9efbdeb14f4ed9b17ae807907e1e9_u128, + ), + (f128::INFINITY, f128::INFINITY.to_bits()), + ]; + + for (input, output) in cases { + assert_biteq!( + sqrtf128(input), + f128::from_bits(output), + "input: {input:?} ({:#018x})", + input.to_bits() + ); + } + } } diff --git a/library/compiler-builtins/libm/src/math/trunc.rs b/library/compiler-builtins/libm/src/math/trunc.rs index 20d52a111a120..a328c2f8f7d08 100644 --- a/library/compiler-builtins/libm/src/math/trunc.rs +++ b/library/compiler-builtins/libm/src/math/trunc.rs @@ -1,10 +1,12 @@ +use super::generic; + /// Rounds the number toward 0 to the closest integral value (f16). /// /// This effectively removes the decimal part of the number, leaving the integral part. #[cfg(f16_enabled)] #[cfg_attr(assert_no_panic, no_panic::no_panic)] pub fn truncf16(x: f16) -> f16 { - super::generic::trunc(x) + generic::trunc_status(x).val } /// Rounds the number toward 0 to the closest integral value (f32). @@ -18,7 +20,7 @@ pub fn truncf(x: f32) -> f32 { args: x, } - super::generic::trunc(x) + generic::trunc_status(x).val } /// Rounds the number toward 0 to the closest integral value (f64). @@ -32,7 +34,7 @@ pub fn trunc(x: f64) -> f64 { args: x, } - super::generic::trunc(x) + generic::trunc_status(x).val } /// Rounds the number toward 0 to the closest integral value (f128). @@ -41,13 +43,91 @@ pub fn trunc(x: f64) -> f64 { #[cfg(f128_enabled)] #[cfg_attr(assert_no_panic, no_panic::no_panic)] pub fn truncf128(x: f128) -> f128 { - super::generic::trunc(x) + generic::trunc_status(x).val } #[cfg(test)] mod tests { + use super::*; + use crate::support::{Float, FpResult, Hex, Status}; + + macro_rules! cases { + ($f:ty) => { + [ + // roundtrip + (0.0, 0.0, Status::OK), + (-0.0, -0.0, Status::OK), + (1.0, 1.0, Status::OK), + (-1.0, -1.0, Status::OK), + (<$f>::INFINITY, <$f>::INFINITY, Status::OK), + (<$f>::NEG_INFINITY, <$f>::NEG_INFINITY, Status::OK), + // with rounding + (0.1, 0.0, Status::INEXACT), + (-0.1, -0.0, Status::INEXACT), + (0.5, 0.0, Status::INEXACT), + (-0.5, -0.0, Status::INEXACT), + (0.9, 0.0, Status::INEXACT), + (-0.9, -0.0, Status::INEXACT), + (1.1, 1.0, Status::INEXACT), + (-1.1, -1.0, Status::INEXACT), + (1.5, 1.0, Status::INEXACT), + (-1.5, -1.0, Status::INEXACT), + (1.9, 1.0, Status::INEXACT), + (-1.9, -1.0, Status::INEXACT), + ] + }; + } + + #[track_caller] + fn check(cases: &[(F, F, Status)]) { + for &(x, exp_res, exp_stat) in cases { + let FpResult { val, status } = generic::trunc_status(x); + assert_biteq!(val, exp_res, "{x:?} {}", Hex(x)); + assert_eq!( + status, + exp_stat, + "{x:?} {} -> {exp_res:?} {}", + Hex(x), + Hex(exp_res) + ); + } + } + + #[test] + #[cfg(f16_enabled)] + fn check_f16() { + check::(&cases!(f16)); + check::(&[ + (hf16!("0x1p10"), hf16!("0x1p10"), Status::OK), + (hf16!("-0x1p10"), hf16!("-0x1p10"), Status::OK), + ]); + } + + #[test] + fn check_f32() { + check::(&cases!(f32)); + check::(&[ + (hf32!("0x1p23"), hf32!("0x1p23"), Status::OK), + (hf32!("-0x1p23"), hf32!("-0x1p23"), Status::OK), + ]); + } + + #[test] + fn check_f64() { + check::(&cases!(f64)); + check::(&[ + (hf64!("0x1p52"), hf64!("0x1p52"), Status::OK), + (hf64!("-0x1p52"), hf64!("-0x1p52"), Status::OK), + ]); + } + #[test] - fn sanity_check() { - assert_eq!(super::truncf(1.1), 1.0); + #[cfg(f128_enabled)] + fn spec_tests_f128() { + check::(&cases!(f128)); + check::(&[ + (hf128!("0x1p112"), hf128!("0x1p112"), Status::OK), + (hf128!("-0x1p112"), hf128!("-0x1p112"), Status::OK), + ]); } } From 9673c6cd4e5404a73b40e1a76be00b9d3164ab5a Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Mon, 30 Mar 2026 02:12:52 -0500 Subject: [PATCH 051/183] libm: Clean up an unused type parameter Recent changes made clippy flag this parameter as unused. --- library/compiler-builtins/libm/src/math/generic/sqrt.rs | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/library/compiler-builtins/libm/src/math/generic/sqrt.rs b/library/compiler-builtins/libm/src/math/generic/sqrt.rs index 0a0d35a8a6226..013f6c097487f 100644 --- a/library/compiler-builtins/libm/src/math/generic/sqrt.rs +++ b/library/compiler-builtins/libm/src/math/generic/sqrt.rs @@ -150,17 +150,17 @@ where let s1_u2: F::ISet1 = ((m_u2) >> (F::BITS - F::ISet1::BITS)).cast(); // Perform iterations, if any, at quarter width (used for `f128`). - let (r1_u0, _s1_u2) = goldschmidt::(r1_u0, s1_u2, F::SET1_ROUNDS, false); + let (r1_u0, _s1_u2) = goldschmidt::(r1_u0, s1_u2, F::SET1_ROUNDS, false); // Widen values and perform iterations at half width (used for `f64` and `f128`). let r2_u0: F::ISet2 = F::ISet2::from(r1_u0) << (F::ISet2::BITS - F::ISet1::BITS); let s2_u2: F::ISet2 = ((m_u2) >> (F::BITS - F::ISet2::BITS)).cast(); - let (r2_u0, _s2_u2) = goldschmidt::(r2_u0, s2_u2, F::SET2_ROUNDS, false); + let (r2_u0, _s2_u2) = goldschmidt::(r2_u0, s2_u2, F::SET2_ROUNDS, false); // Perform final iterations at full width (used for all float types). let r_u0: F::Int = F::Int::from(r2_u0) << (F::BITS - F::ISet2::BITS); let s_u2: F::Int = m_u2; - let (_r_u0, s_u2) = goldschmidt::(r_u0, s_u2, F::FINAL_ROUNDS, true); + let (_r_u0, s_u2) = goldschmidt::(r_u0, s_u2, F::FINAL_ROUNDS, true); // Shift back to mantissa position. let mut m = s_u2 >> (F::EXP_BITS - 2); @@ -236,9 +236,8 @@ fn wmulh(a: I, b: I) -> I { /// Note that performance relies on the optimizer being able to unroll these loops (reasonably /// trivial, `count` is a constant when called). #[inline] -fn goldschmidt(mut r_u0: I, mut s_u2: I, count: u32, final_set: bool) -> (I, I) +fn goldschmidt(mut r_u0: I, mut s_u2: I, count: u32, final_set: bool) -> (I, I) where - F: SqrtHelper, I: HInt + From, { let three_u2 = I::from(0b11u8) << (I::BITS - 2); From c87cad8477c3c623b844900715fa7a5c20db486f Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Mon, 30 Mar 2026 03:07:55 -0500 Subject: [PATCH 052/183] c-b: Use libm `Int`, `MinInt`, `u256`, and related items The libm and c-b versions of these are (intentionally) near identical. Switch c-b to use the libm versions rather than having its own definitions, which allows cleaning up a significant amount of code. --- .../builtins-test/src/lib.rs | 2 +- .../builtins-test/tests/big.rs | 134 -------- .../builtins-test/tests/conv.rs | 6 +- .../builtins-test/tests/lse.rs | 2 +- .../compiler-builtins/src/float/add.rs | 2 +- .../compiler-builtins/src/float/cmp.rs | 3 +- .../compiler-builtins/src/float/conv.rs | 2 +- .../compiler-builtins/src/float/div.rs | 2 +- .../compiler-builtins/src/float/extend.rs | 2 +- .../compiler-builtins/src/float/mul.rs | 2 +- .../compiler-builtins/src/float/pow.rs | 2 +- .../compiler-builtins/src/float/traits.rs | 2 +- .../compiler-builtins/src/float/trunc.rs | 2 +- .../compiler-builtins/src/int/addsub.rs | 2 +- .../compiler-builtins/src/int/big.rs | 295 ------------------ .../src/int/leading_zeros.rs | 2 +- .../compiler-builtins/src/int/mod.rs | 8 - .../compiler-builtins/src/int/mul.rs | 2 +- .../compiler-builtins/src/int/shift.rs | 2 +- .../src/int/trailing_zeros.rs | 2 +- .../compiler-builtins/src/int/traits.rs | 99 ------ .../compiler-builtins/src/lib.rs | 3 + 22 files changed, 22 insertions(+), 556 deletions(-) delete mode 100644 library/compiler-builtins/builtins-test/tests/big.rs delete mode 100644 library/compiler-builtins/compiler-builtins/src/int/big.rs delete mode 100644 library/compiler-builtins/compiler-builtins/src/int/traits.rs diff --git a/library/compiler-builtins/builtins-test/src/lib.rs b/library/compiler-builtins/builtins-test/src/lib.rs index b9ad649f88dd7..e66887871bf78 100644 --- a/library/compiler-builtins/builtins-test/src/lib.rs +++ b/library/compiler-builtins/builtins-test/src/lib.rs @@ -20,7 +20,7 @@ pub mod bench; extern crate alloc; use compiler_builtins::float::Float; -use compiler_builtins::int::{Int, MinInt}; +use compiler_builtins::support::{Int, MinInt}; use rand_xoshiro::Xoshiro128StarStar; use rand_xoshiro::rand_core::{Rng, SeedableRng}; diff --git a/library/compiler-builtins/builtins-test/tests/big.rs b/library/compiler-builtins/builtins-test/tests/big.rs deleted file mode 100644 index d1ae88bd16485..0000000000000 --- a/library/compiler-builtins/builtins-test/tests/big.rs +++ /dev/null @@ -1,134 +0,0 @@ -use compiler_builtins::int::{HInt, MinInt, i256, u256}; - -const LOHI_SPLIT: u128 = 0xaaaaaaaaaaaaaaaaffffffffffffffff; - -/// Print a `u256` as hex since we can't add format implementations -fn hexu(v: u256) -> String { - format!( - "0x{:016x}{:016x}{:016x}{:016x}", - v.0[3], v.0[2], v.0[1], v.0[0] - ) -} - -#[test] -fn widen_u128() { - assert_eq!(u128::MAX.widen(), u256([u64::MAX, u64::MAX, 0, 0])); - assert_eq!( - LOHI_SPLIT.widen(), - u256([u64::MAX, 0xaaaaaaaaaaaaaaaa, 0, 0]) - ); -} - -#[test] -fn widen_i128() { - assert_eq!((-1i128).widen(), u256::MAX.signed()); - assert_eq!( - (LOHI_SPLIT as i128).widen(), - i256([u64::MAX, 0xaaaaaaaaaaaaaaaa, u64::MAX, u64::MAX]) - ); - assert_eq!((-1i128).zero_widen().unsigned(), (u128::MAX).widen()); -} - -#[test] -fn widen_mul_u128() { - let tests = [ - (u128::MAX / 2, 2_u128, u256([u64::MAX - 1, u64::MAX, 0, 0])), - (u128::MAX, 2_u128, u256([u64::MAX - 1, u64::MAX, 1, 0])), - (u128::MAX, u128::MAX, u256([1, 0, u64::MAX - 1, u64::MAX])), - (u128::MIN, u128::MIN, u256::ZERO), - (1234, 0, u256::ZERO), - (0, 1234, u256::ZERO), - ]; - - let mut errors = Vec::new(); - for (i, (a, b, exp)) in tests.iter().copied().enumerate() { - let res = a.widen_mul(b); - let res_z = a.zero_widen_mul(b); - assert_eq!(res, res_z); - if res != exp { - errors.push((i, a, b, exp, res)); - } - } - - for (i, a, b, exp, res) in &errors { - eprintln!( - "FAILURE ({i}): {a:#034x} * {b:#034x} = {} got {}", - hexu(*exp), - hexu(*res) - ); - } - assert!(errors.is_empty()); -} - -#[test] -fn not_u128() { - assert_eq!(!u256::ZERO, u256::MAX); -} - -#[test] -fn shr_u128() { - let only_low = [ - 1, - u16::MAX.into(), - u32::MAX.into(), - u64::MAX.into(), - u128::MAX, - ]; - - let mut errors = Vec::new(); - - for a in only_low { - for perturb in 0..10 { - let a = a.saturating_add(perturb); - for shift in 0..128 { - let res = a.widen() >> shift; - let expected = (a >> shift).widen(); - if res != expected { - errors.push((a.widen(), shift, res, expected)); - } - } - } - } - - let check = [ - ( - u256::MAX, - 1, - u256([u64::MAX, u64::MAX, u64::MAX, u64::MAX >> 1]), - ), - ( - u256::MAX, - 5, - u256([u64::MAX, u64::MAX, u64::MAX, u64::MAX >> 5]), - ), - (u256::MAX, 63, u256([u64::MAX, u64::MAX, u64::MAX, 1])), - (u256::MAX, 64, u256([u64::MAX, u64::MAX, u64::MAX, 0])), - (u256::MAX, 65, u256([u64::MAX, u64::MAX, u64::MAX >> 1, 0])), - (u256::MAX, 127, u256([u64::MAX, u64::MAX, 1, 0])), - (u256::MAX, 128, u256([u64::MAX, u64::MAX, 0, 0])), - (u256::MAX, 129, u256([u64::MAX, u64::MAX >> 1, 0, 0])), - (u256::MAX, 191, u256([u64::MAX, 1, 0, 0])), - (u256::MAX, 192, u256([u64::MAX, 0, 0, 0])), - (u256::MAX, 193, u256([u64::MAX >> 1, 0, 0, 0])), - (u256::MAX, 191, u256([u64::MAX, 1, 0, 0])), - (u256::MAX, 254, u256([0b11, 0, 0, 0])), - (u256::MAX, 255, u256([1, 0, 0, 0])), - ]; - - for (input, shift, expected) in check { - let res = input >> shift; - if res != expected { - errors.push((input, shift, res, expected)); - } - } - - for (a, b, res, expected) in &errors { - eprintln!( - "FAILURE: {} >> {b} = {} got {}", - hexu(*a), - hexu(*expected), - hexu(*res), - ); - } - assert!(errors.is_empty()); -} diff --git a/library/compiler-builtins/builtins-test/tests/conv.rs b/library/compiler-builtins/builtins-test/tests/conv.rs index 0fd15ad3ee662..b94a2ce8de5f4 100644 --- a/library/compiler-builtins/builtins-test/tests/conv.rs +++ b/library/compiler-builtins/builtins-test/tests/conv.rs @@ -18,7 +18,7 @@ mod i_to_f { #[test] fn $fn() { use compiler_builtins::float::conv::$fn; - use compiler_builtins::int::Int; + use compiler_builtins::support::Int; fuzz(N, |x: $i_ty| { let f0 = apfloat_fallback!( @@ -27,7 +27,7 @@ mod i_to_f { // When the builtin is not available, we need to use a different conversion // method (since apfloat doesn't support `as` casting). |x: $i_ty| { - use compiler_builtins::int::MinInt; + use compiler_builtins::support::MinInt; let apf = if <$i_ty>::SIGNED { FloatTy::from_i128(x.try_into().unwrap()).value @@ -155,7 +155,7 @@ mod f_to_i { // When the builtin is not available, we need to use a different conversion // method (since apfloat doesn't support `as` casting). |x: $f_ty| { - use compiler_builtins::int::MinInt; + use compiler_builtins::support::MinInt; let apf = FloatTy::from_bits(x.to_bits().into()); let bits: usize = <$i_ty>::BITS.try_into().unwrap(); diff --git a/library/compiler-builtins/builtins-test/tests/lse.rs b/library/compiler-builtins/builtins-test/tests/lse.rs index d408fe193bcff..7fdc6da8bc25a 100644 --- a/library/compiler-builtins/builtins-test/tests/lse.rs +++ b/library/compiler-builtins/builtins-test/tests/lse.rs @@ -6,7 +6,7 @@ use std::sync::Mutex; use compiler_builtins::aarch64_outline_atomics::{get_have_lse_atomics, set_have_lse_atomics}; -use compiler_builtins::int::{Int, MinInt}; +use compiler_builtins::support::{Int, MinInt}; use compiler_builtins::{foreach_bytes, foreach_ordering}; #[track_caller] diff --git a/library/compiler-builtins/compiler-builtins/src/float/add.rs b/library/compiler-builtins/compiler-builtins/src/float/add.rs index acdcd2ebe3133..88b2fc80d9d6c 100644 --- a/library/compiler-builtins/compiler-builtins/src/float/add.rs +++ b/library/compiler-builtins/compiler-builtins/src/float/add.rs @@ -1,5 +1,5 @@ use crate::float::Float; -use crate::int::{CastFrom, CastInto, Int, MinInt}; +use crate::support::{CastFrom, CastInto, Int, MinInt}; /// Returns `a + b` fn add(a: F, b: F) -> F diff --git a/library/compiler-builtins/compiler-builtins/src/float/cmp.rs b/library/compiler-builtins/compiler-builtins/src/float/cmp.rs index 3587d78d1396e..88ff54535c6ce 100644 --- a/library/compiler-builtins/compiler-builtins/src/float/cmp.rs +++ b/library/compiler-builtins/compiler-builtins/src/float/cmp.rs @@ -1,8 +1,7 @@ #![allow(unreachable_code)] use crate::float::Float; -use crate::int::MinInt; -use crate::support::cfg_if; +use crate::support::{MinInt, cfg_if}; // Taken from LLVM config [1], which should match GCC's `CMPtype` [2]. // diff --git a/library/compiler-builtins/compiler-builtins/src/float/conv.rs b/library/compiler-builtins/compiler-builtins/src/float/conv.rs index 75ea7ce02424a..e6456a5f9f1a8 100644 --- a/library/compiler-builtins/compiler-builtins/src/float/conv.rs +++ b/library/compiler-builtins/compiler-builtins/src/float/conv.rs @@ -1,7 +1,7 @@ use core::ops::Neg; use super::Float; -use crate::int::{CastFrom, CastInto, Int, MinInt}; +use crate::support::{CastFrom, CastInto, Int, MinInt}; /// Conversions from integers to floats. /// diff --git a/library/compiler-builtins/compiler-builtins/src/float/div.rs b/library/compiler-builtins/compiler-builtins/src/float/div.rs index fc1fc085105a7..6f3939875a3ea 100644 --- a/library/compiler-builtins/compiler-builtins/src/float/div.rs +++ b/library/compiler-builtins/compiler-builtins/src/float/div.rs @@ -84,7 +84,7 @@ use core::ops; use super::HalfRep; use crate::float::Float; -use crate::int::{CastFrom, CastInto, DInt, HInt, Int, MinInt}; +use crate::support::{CastFrom, CastInto, DInt, HInt, Int, MinInt}; fn div(a: F, b: F) -> F where diff --git a/library/compiler-builtins/compiler-builtins/src/float/extend.rs b/library/compiler-builtins/compiler-builtins/src/float/extend.rs index c4f1fe30e0ea8..02cd743d14ebe 100644 --- a/library/compiler-builtins/compiler-builtins/src/float/extend.rs +++ b/library/compiler-builtins/compiler-builtins/src/float/extend.rs @@ -1,5 +1,5 @@ use crate::float::Float; -use crate::int::{CastInto, Int, MinInt}; +use crate::support::{CastInto, Int, MinInt}; /// Generic conversion from a narrower to a wider IEEE-754 floating-point type fn extend(a: F) -> R diff --git a/library/compiler-builtins/compiler-builtins/src/float/mul.rs b/library/compiler-builtins/compiler-builtins/src/float/mul.rs index 49a2414eb5c69..7fb57ce702574 100644 --- a/library/compiler-builtins/compiler-builtins/src/float/mul.rs +++ b/library/compiler-builtins/compiler-builtins/src/float/mul.rs @@ -1,5 +1,5 @@ use crate::float::Float; -use crate::int::{CastInto, DInt, HInt, Int, MinInt}; +use crate::support::{CastInto, DInt, HInt, Int, MinInt}; fn mul(a: F, b: F) -> F where diff --git a/library/compiler-builtins/compiler-builtins/src/float/pow.rs b/library/compiler-builtins/compiler-builtins/src/float/pow.rs index 6997a9c213c59..4c58301fff33f 100644 --- a/library/compiler-builtins/compiler-builtins/src/float/pow.rs +++ b/library/compiler-builtins/compiler-builtins/src/float/pow.rs @@ -1,5 +1,5 @@ use crate::float::Float; -use crate::int::Int; +use crate::support::Int; /// Returns `a` raised to the power `b` fn pow(a: F, b: i32) -> F { diff --git a/library/compiler-builtins/compiler-builtins/src/float/traits.rs b/library/compiler-builtins/compiler-builtins/src/float/traits.rs index a30d20900b1c4..8bea3e900ddae 100644 --- a/library/compiler-builtins/compiler-builtins/src/float/traits.rs +++ b/library/compiler-builtins/compiler-builtins/src/float/traits.rs @@ -1,6 +1,6 @@ use core::ops; -use crate::int::{DInt, Int, MinInt}; +use crate::support::{DInt, Int, MinInt}; /// Wrapper to extract the integer type half of the float's size pub type HalfRep = <::Int as DInt>::H; diff --git a/library/compiler-builtins/compiler-builtins/src/float/trunc.rs b/library/compiler-builtins/compiler-builtins/src/float/trunc.rs index 93db5d8bbdeb1..a3f578d0f723e 100644 --- a/library/compiler-builtins/compiler-builtins/src/float/trunc.rs +++ b/library/compiler-builtins/compiler-builtins/src/float/trunc.rs @@ -1,5 +1,5 @@ use crate::float::Float; -use crate::int::{CastInto, Int, MinInt}; +use crate::support::{CastInto, Int, MinInt}; fn trunc(a: F) -> R where diff --git a/library/compiler-builtins/compiler-builtins/src/int/addsub.rs b/library/compiler-builtins/compiler-builtins/src/int/addsub.rs index b2b21fc2c4401..ab5e8e1b5d873 100644 --- a/library/compiler-builtins/compiler-builtins/src/int/addsub.rs +++ b/library/compiler-builtins/compiler-builtins/src/int/addsub.rs @@ -1,4 +1,4 @@ -use crate::int::{DInt, Int, MinInt}; +use crate::support::{DInt, Int, MinInt}; trait UAddSub: DInt + Int { fn uadd(self, other: Self) -> Self { diff --git a/library/compiler-builtins/compiler-builtins/src/int/big.rs b/library/compiler-builtins/compiler-builtins/src/int/big.rs deleted file mode 100644 index 8e06009090c09..0000000000000 --- a/library/compiler-builtins/compiler-builtins/src/int/big.rs +++ /dev/null @@ -1,295 +0,0 @@ -//! Integers used for wide operations, larger than `u128`. - -#![allow(unused)] - -use core::{fmt, ops}; - -use crate::int::{DInt, HInt, Int, MinInt}; - -const WORD_LO_MASK: u64 = 0x00000000ffffffff; -const WORD_HI_MASK: u64 = 0xffffffff00000000; -const WORD_FULL_MASK: u64 = 0xffffffffffffffff; -const U128_LO_MASK: u128 = u64::MAX as u128; -const U128_HI_MASK: u128 = (u64::MAX as u128) << 64; - -/// A 256-bit unsigned integer represented as 4 64-bit limbs. -/// -/// Each limb is a native-endian number, but the array is little-limb-endian. -#[allow(non_camel_case_types)] -#[derive(Clone, Copy, Debug, PartialEq, PartialOrd)] -pub struct u256(pub [u64; 4]); - -impl u256 { - pub const MAX: Self = Self([u64::MAX, u64::MAX, u64::MAX, u64::MAX]); - - /// Reinterpret as a signed integer - pub fn signed(self) -> i256 { - i256(self.0) - } -} - -/// A 256-bit signed integer represented as 4 64-bit limbs. -/// -/// Each limb is a native-endian number, but the array is little-limb-endian. -#[allow(non_camel_case_types)] -#[derive(Clone, Copy, Debug, PartialEq, PartialOrd)] -pub struct i256(pub [u64; 4]); - -impl i256 { - /// Reinterpret as an unsigned integer - pub fn unsigned(self) -> u256 { - u256(self.0) - } -} - -impl MinInt for u256 { - type OtherSign = i256; - - type Unsigned = u256; - - const SIGNED: bool = false; - const BITS: u32 = 256; - const ZERO: Self = Self([0u64; 4]); - const ONE: Self = Self([1, 0, 0, 0]); - const MIN: Self = Self([0u64; 4]); - const MAX: Self = Self([u64::MAX; 4]); -} - -impl MinInt for i256 { - type OtherSign = u256; - - type Unsigned = u256; - - const SIGNED: bool = false; - const BITS: u32 = 256; - const ZERO: Self = Self([0u64; 4]); - const ONE: Self = Self([1, 0, 0, 0]); - const MIN: Self = Self([0, 0, 0, 1 << 63]); - const MAX: Self = Self([u64::MAX, u64::MAX, u64::MAX, u64::MAX >> 1]); -} - -macro_rules! impl_common { - ($ty:ty) => { - impl ops::BitOr for $ty { - type Output = Self; - - fn bitor(mut self, rhs: Self) -> Self::Output { - self.0[0] |= rhs.0[0]; - self.0[1] |= rhs.0[1]; - self.0[2] |= rhs.0[2]; - self.0[3] |= rhs.0[3]; - self - } - } - - impl ops::Not for $ty { - type Output = Self; - - fn not(self) -> Self::Output { - Self([!self.0[0], !self.0[1], !self.0[2], !self.0[3]]) - } - } - - impl ops::Shl for $ty { - type Output = Self; - - fn shl(self, rhs: u32) -> Self::Output { - unimplemented!("only used to meet trait bounds") - } - } - }; -} - -impl_common!(i256); -impl_common!(u256); - -impl ops::Shr for u256 { - type Output = Self; - - fn shr(self, rhs: u32) -> Self::Output { - assert!(rhs < Self::BITS, "attempted to shift right with overflow"); - - if rhs == 0 { - return self; - } - - let mut ret = self; - let byte_shift = rhs / 64; - let bit_shift = rhs % 64; - - for idx in 0..4 { - let base_idx = idx + byte_shift as usize; - - let Some(base) = ret.0.get(base_idx) else { - ret.0[idx] = 0; - continue; - }; - - let mut new_val = base >> bit_shift; - - if let Some(new) = ret.0.get(base_idx + 1) { - new_val |= new.overflowing_shl(64 - bit_shift).0; - } - - ret.0[idx] = new_val; - } - - ret - } -} - -macro_rules! word { - (1, $val:expr) => { - (($val >> (32 * 3)) & Self::from(WORD_LO_MASK)) as u64 - }; - (2, $val:expr) => { - (($val >> (32 * 2)) & Self::from(WORD_LO_MASK)) as u64 - }; - (3, $val:expr) => { - (($val >> (32 * 1)) & Self::from(WORD_LO_MASK)) as u64 - }; - (4, $val:expr) => { - (($val >> (32 * 0)) & Self::from(WORD_LO_MASK)) as u64 - }; -} - -impl HInt for u128 { - type D = u256; - - fn widen(self) -> Self::D { - let w0 = self & u128::from(u64::MAX); - let w1 = (self >> u64::BITS) & u128::from(u64::MAX); - u256([w0 as u64, w1 as u64, 0, 0]) - } - - fn zero_widen(self) -> Self::D { - self.widen() - } - - fn zero_widen_mul(self, rhs: Self) -> Self::D { - let product11: u64 = word!(1, self) * word!(1, rhs); - let product12: u64 = word!(1, self) * word!(2, rhs); - let product13: u64 = word!(1, self) * word!(3, rhs); - let product14: u64 = word!(1, self) * word!(4, rhs); - let product21: u64 = word!(2, self) * word!(1, rhs); - let product22: u64 = word!(2, self) * word!(2, rhs); - let product23: u64 = word!(2, self) * word!(3, rhs); - let product24: u64 = word!(2, self) * word!(4, rhs); - let product31: u64 = word!(3, self) * word!(1, rhs); - let product32: u64 = word!(3, self) * word!(2, rhs); - let product33: u64 = word!(3, self) * word!(3, rhs); - let product34: u64 = word!(3, self) * word!(4, rhs); - let product41: u64 = word!(4, self) * word!(1, rhs); - let product42: u64 = word!(4, self) * word!(2, rhs); - let product43: u64 = word!(4, self) * word!(3, rhs); - let product44: u64 = word!(4, self) * word!(4, rhs); - - let sum0: u128 = u128::from(product44); - let sum1: u128 = u128::from(product34) + u128::from(product43); - let sum2: u128 = u128::from(product24) + u128::from(product33) + u128::from(product42); - let sum3: u128 = u128::from(product14) - + u128::from(product23) - + u128::from(product32) - + u128::from(product41); - let sum4: u128 = u128::from(product13) + u128::from(product22) + u128::from(product31); - let sum5: u128 = u128::from(product12) + u128::from(product21); - let sum6: u128 = u128::from(product11); - - let r0: u128 = - (sum0 & u128::from(WORD_FULL_MASK)) + ((sum1 & u128::from(WORD_LO_MASK)) << 32); - let r1: u128 = (sum0 >> 64) - + ((sum1 >> 32) & u128::from(WORD_FULL_MASK)) - + (sum2 & u128::from(WORD_FULL_MASK)) - + ((sum3 << 32) & u128::from(WORD_HI_MASK)); - - let (lo, carry) = r0.overflowing_add(r1 << 64); - let hi = (r1 >> 64) - + (sum1 >> 96) - + (sum2 >> 64) - + (sum3 >> 32) - + sum4 - + (sum5 << 32) - + (sum6 << 64) - + u128::from(carry); - - u256([ - (lo & U128_LO_MASK) as u64, - ((lo >> 64) & U128_LO_MASK) as u64, - (hi & U128_LO_MASK) as u64, - ((hi >> 64) & U128_LO_MASK) as u64, - ]) - } - - fn widen_mul(self, rhs: Self) -> Self::D { - self.zero_widen_mul(rhs) - } - - fn widen_hi(self) -> Self::D { - self.widen() << ::BITS - } -} - -impl HInt for i128 { - type D = i256; - - fn widen(self) -> Self::D { - let mut ret = self.unsigned().zero_widen().signed(); - if self.is_negative() { - ret.0[2] = u64::MAX; - ret.0[3] = u64::MAX; - } - ret - } - - fn zero_widen(self) -> Self::D { - self.unsigned().zero_widen().signed() - } - - fn zero_widen_mul(self, rhs: Self) -> Self::D { - self.unsigned().zero_widen_mul(rhs.unsigned()).signed() - } - - fn widen_mul(self, rhs: Self) -> Self::D { - unimplemented!("signed i128 widening multiply is not used") - } - - fn widen_hi(self) -> Self::D { - self.widen() << ::BITS - } -} - -impl DInt for u256 { - type H = u128; - - fn lo(self) -> Self::H { - let mut tmp = [0u8; 16]; - tmp[..8].copy_from_slice(&self.0[0].to_le_bytes()); - tmp[8..].copy_from_slice(&self.0[1].to_le_bytes()); - u128::from_le_bytes(tmp) - } - - fn hi(self) -> Self::H { - let mut tmp = [0u8; 16]; - tmp[..8].copy_from_slice(&self.0[2].to_le_bytes()); - tmp[8..].copy_from_slice(&self.0[3].to_le_bytes()); - u128::from_le_bytes(tmp) - } -} - -impl DInt for i256 { - type H = i128; - - fn lo(self) -> Self::H { - let mut tmp = [0u8; 16]; - tmp[..8].copy_from_slice(&self.0[0].to_le_bytes()); - tmp[8..].copy_from_slice(&self.0[1].to_le_bytes()); - i128::from_le_bytes(tmp) - } - - fn hi(self) -> Self::H { - let mut tmp = [0u8; 16]; - tmp[..8].copy_from_slice(&self.0[2].to_le_bytes()); - tmp[8..].copy_from_slice(&self.0[3].to_le_bytes()); - i128::from_le_bytes(tmp) - } -} diff --git a/library/compiler-builtins/compiler-builtins/src/int/leading_zeros.rs b/library/compiler-builtins/compiler-builtins/src/int/leading_zeros.rs index aa5cb39935ad8..3b920ecff6b20 100644 --- a/library/compiler-builtins/compiler-builtins/src/int/leading_zeros.rs +++ b/library/compiler-builtins/compiler-builtins/src/int/leading_zeros.rs @@ -9,7 +9,7 @@ pub use implementation::{leading_zeros_default, leading_zeros_riscv}; pub(crate) use implementation::{leading_zeros_default, leading_zeros_riscv}; mod implementation { - use crate::int::{CastFrom, Int}; + use crate::support::{CastFrom, Int}; /// Returns the number of leading binary zeros in `x`. #[allow(dead_code)] diff --git a/library/compiler-builtins/compiler-builtins/src/int/mod.rs b/library/compiler-builtins/compiler-builtins/src/int/mod.rs index 518ccb23f8009..cd4011a933815 100644 --- a/library/compiler-builtins/compiler-builtins/src/int/mod.rs +++ b/library/compiler-builtins/compiler-builtins/src/int/mod.rs @@ -1,18 +1,10 @@ mod specialized_div_rem; pub mod addsub; -mod big; pub mod bswap; pub mod leading_zeros; pub mod mul; pub mod sdiv; pub mod shift; pub mod trailing_zeros; -mod traits; pub mod udiv; - -pub use big::{i256, u256}; -#[cfg(not(feature = "unstable-public-internals"))] -pub(crate) use traits::{CastFrom, CastInto, DInt, HInt, Int, MinInt}; -#[cfg(feature = "unstable-public-internals")] -pub use traits::{CastFrom, CastInto, DInt, HInt, Int, MinInt}; diff --git a/library/compiler-builtins/compiler-builtins/src/int/mul.rs b/library/compiler-builtins/compiler-builtins/src/int/mul.rs index 7db09beb89e83..9331ab60a4fc1 100644 --- a/library/compiler-builtins/compiler-builtins/src/int/mul.rs +++ b/library/compiler-builtins/compiler-builtins/src/int/mul.rs @@ -1,4 +1,4 @@ -use crate::int::{DInt, HInt, Int}; +use crate::support::{DInt, HInt, Int}; trait Mul: DInt + Int where diff --git a/library/compiler-builtins/compiler-builtins/src/int/shift.rs b/library/compiler-builtins/compiler-builtins/src/int/shift.rs index a85c1b33d6714..f5cac9ad4e367 100644 --- a/library/compiler-builtins/compiler-builtins/src/int/shift.rs +++ b/library/compiler-builtins/compiler-builtins/src/int/shift.rs @@ -1,4 +1,4 @@ -use crate::int::{DInt, HInt, Int, MinInt}; +use crate::support::{DInt, HInt, Int, MinInt}; trait Ashl: DInt { /// Returns `a << b`, requires `b < Self::BITS` diff --git a/library/compiler-builtins/compiler-builtins/src/int/trailing_zeros.rs b/library/compiler-builtins/compiler-builtins/src/int/trailing_zeros.rs index 1b0ae5b73ad24..f42e9926dbb11 100644 --- a/library/compiler-builtins/compiler-builtins/src/int/trailing_zeros.rs +++ b/library/compiler-builtins/compiler-builtins/src/int/trailing_zeros.rs @@ -4,7 +4,7 @@ pub use implementation::trailing_zeros; pub(crate) use implementation::trailing_zeros; mod implementation { - use crate::int::{CastFrom, Int}; + use crate::support::{CastFrom, Int}; /// Returns number of trailing binary zeros in `x`. #[allow(dead_code)] diff --git a/library/compiler-builtins/compiler-builtins/src/int/traits.rs b/library/compiler-builtins/compiler-builtins/src/int/traits.rs deleted file mode 100644 index 25b9718ad53fb..0000000000000 --- a/library/compiler-builtins/compiler-builtins/src/int/traits.rs +++ /dev/null @@ -1,99 +0,0 @@ -pub use crate::support::{CastFrom, CastInto, Int, MinInt}; - -/// Trait for integers twice the bit width of another integer. This is implemented for all -/// primitives except for `u8`, because there is not a smaller primitive. -pub trait DInt: MinInt { - /// Integer that is half the bit width of the integer this trait is implemented for - type H: HInt; - - /// Returns the low half of `self` - fn lo(self) -> Self::H; - /// Returns the high half of `self` - fn hi(self) -> Self::H; - /// Returns the low and high halves of `self` as a tuple - fn lo_hi(self) -> (Self::H, Self::H) { - (self.lo(), self.hi()) - } - /// Constructs an integer using lower and higher half parts - fn from_lo_hi(lo: Self::H, hi: Self::H) -> Self { - lo.zero_widen() | hi.widen_hi() - } -} - -/// Trait for integers half the bit width of another integer. This is implemented for all -/// primitives except for `u128`, because it there is not a larger primitive. -pub trait HInt: Int { - /// Integer that is double the bit width of the integer this trait is implemented for - type D: DInt + MinInt; - - // NB: some of the below methods could have default implementations (e.g. `widen_hi`), but for - // unknown reasons this can cause infinite recursion when optimizations are disabled. See - // for context. - - /// Widens (using default extension) the integer to have double bit width - fn widen(self) -> Self::D; - /// Widens (zero extension only) the integer to have double bit width. This is needed to get - /// around problems with associated type bounds (such as `Int`) being unstable - fn zero_widen(self) -> Self::D; - /// Widens the integer to have double bit width and shifts the integer into the higher bits - fn widen_hi(self) -> Self::D; - /// Widening multiplication with zero widening. This cannot overflow. - fn zero_widen_mul(self, rhs: Self) -> Self::D; - /// Widening multiplication. This cannot overflow. - fn widen_mul(self, rhs: Self) -> Self::D; -} - -macro_rules! impl_d_int { - ($($X:ident $D:ident),*) => { - $( - impl DInt for $D { - type H = $X; - - fn lo(self) -> Self::H { - self as $X - } - fn hi(self) -> Self::H { - (self >> <$X as MinInt>::BITS) as $X - } - } - )* - }; -} - -macro_rules! impl_h_int { - ($($H:ident $uH:ident $X:ident),*) => { - $( - impl HInt for $H { - type D = $X; - - fn widen(self) -> Self::D { - self as $X - } - fn zero_widen(self) -> Self::D { - (self as $uH) as $X - } - fn zero_widen_mul(self, rhs: Self) -> Self::D { - self.zero_widen().wrapping_mul(rhs.zero_widen()) - } - fn widen_mul(self, rhs: Self) -> Self::D { - self.widen().wrapping_mul(rhs.widen()) - } - fn widen_hi(self) -> Self::D { - (self as $X) << ::BITS - } - } - )* - }; -} - -impl_d_int!(u8 u16, u16 u32, u32 u64, u64 u128, i8 i16, i16 i32, i32 i64, i64 i128); -impl_h_int!( - u8 u8 u16, - u16 u16 u32, - u32 u32 u64, - u64 u64 u128, - i8 u8 i16, - i16 u16 i32, - i32 u32 i64, - i64 u64 i128 -); diff --git a/library/compiler-builtins/compiler-builtins/src/lib.rs b/library/compiler-builtins/compiler-builtins/src/lib.rs index 207ec3c19f3ad..81e4a31e8e449 100644 --- a/library/compiler-builtins/compiler-builtins/src/lib.rs +++ b/library/compiler-builtins/compiler-builtins/src/lib.rs @@ -48,6 +48,9 @@ pub mod mem; pub mod sync; // `libm` expects its `support` module to be available in the crate root. +#[cfg(feature = "unstable-public-internals")] +pub use math::libm_math::support; +#[cfg(not(feature = "unstable-public-internals"))] use math::libm_math::support; #[cfg(target_arch = "arm")] From a6aa04cacd13a1c6bb006647792d7bf9905ee1b5 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Mon, 30 Mar 2026 03:38:25 -0500 Subject: [PATCH 053/183] c-b: Use the libm `Float` trait Similar to `Int`, `Float` is very similar between `compiler-builtins` and libm. Remove the c-b version and instead use the libm trait for both crates. --- .../builtins-test/src/bench.rs | 2 +- .../builtins-test/src/lib.rs | 27 ++- .../builtins-test/tests/addsub.rs | 3 +- .../builtins-test/tests/conv.rs | 5 +- .../builtins-test/tests/div_rem.rs | 3 +- .../builtins-test/tests/float_pow.rs | 3 +- .../builtins-test/tests/mul.rs | 3 +- .../compiler-builtins/src/float/add.rs | 3 +- .../compiler-builtins/src/float/cmp.rs | 3 +- .../compiler-builtins/src/float/conv.rs | 3 +- .../compiler-builtins/src/float/div.rs | 4 +- .../compiler-builtins/src/float/extend.rs | 3 +- .../compiler-builtins/src/float/mod.rs | 6 - .../compiler-builtins/src/float/mul.rs | 3 +- .../compiler-builtins/src/float/pow.rs | 3 +- .../compiler-builtins/src/float/sub.rs | 2 +- .../compiler-builtins/src/float/traits.rs | 189 ------------------ .../compiler-builtins/src/float/trunc.rs | 3 +- .../libm-test/src/f8_impl.rs | 8 + library/compiler-builtins/libm/Cargo.toml | 3 +- .../libm/src/math/support/float_traits.rs | 35 +++- .../libm/src/math/support/mod.rs | 2 +- 22 files changed, 72 insertions(+), 244 deletions(-) delete mode 100644 library/compiler-builtins/compiler-builtins/src/float/traits.rs diff --git a/library/compiler-builtins/builtins-test/src/bench.rs b/library/compiler-builtins/builtins-test/src/bench.rs index 4bdcf482cd619..aafcac4fa7913 100644 --- a/library/compiler-builtins/builtins-test/src/bench.rs +++ b/library/compiler-builtins/builtins-test/src/bench.rs @@ -1,7 +1,7 @@ use alloc::vec::Vec; use core::cell::RefCell; -use compiler_builtins::float::Float; +use compiler_builtins::support::Float; /// Fuzz with these many items to ensure equal functions pub const CHECK_ITER_ITEMS: u32 = 10_000; diff --git a/library/compiler-builtins/builtins-test/src/lib.rs b/library/compiler-builtins/builtins-test/src/lib.rs index e66887871bf78..70478f5f6d745 100644 --- a/library/compiler-builtins/builtins-test/src/lib.rs +++ b/library/compiler-builtins/builtins-test/src/lib.rs @@ -19,8 +19,7 @@ pub mod bench; extern crate alloc; -use compiler_builtins::float::Float; -use compiler_builtins::support::{Int, MinInt}; +use compiler_builtins::support::{Float, Int, MinInt}; use rand_xoshiro::Xoshiro128StarStar; use rand_xoshiro::rand_core::{Rng, SeedableRng}; @@ -245,18 +244,18 @@ fn fuzz_float_step(rng: &mut Xoshiro128StarStar, f: &mut F) { let sign = (rng32 & 1) != 0; // exponent fuzzing. Only 4 bits for the selector needed. - let ones = (F::Int::ONE << F::EXP_BITS) - F::Int::ONE; + let ones = F::EXP_SAT; let r0 = (rng32 >> 1) % F::EXP_BITS; let r1 = (rng32 >> 5) % F::EXP_BITS; // custom rotate shift. Note that `F::Int` is unsigned, so we can shift right without smearing // the sign bit. let mask = if r1 == 0 { - ones.wrapping_shr(r0) + ones >> r0 } else { - let tmp = ones.wrapping_shr(r0); - (tmp.wrapping_shl(r1) | tmp.wrapping_shr(F::EXP_BITS - r1)) & ones + let tmp = ones >> r0; + ((tmp << r1) | (tmp >> (F::EXP_BITS - r1))) & ones }; - let mut exp = (f.to_bits() & F::EXP_MASK) >> F::SIG_BITS; + let mut exp = f.ex(); match (rng32 >> 9) % 4 { 0 => exp |= mask, 1 => exp &= mask, @@ -274,13 +273,13 @@ fn fuzz_float_step(rng: &mut Xoshiro128StarStar, f: &mut F) { macro_rules! float_edge_cases { ($F:ident, $case:ident, $inner:block) => { for exponent in [ - F::Int::ZERO, - F::Int::ONE, - F::Int::ONE << (F::EXP_BITS / 2), - (F::Int::ONE << (F::EXP_BITS - 1)) - F::Int::ONE, - F::Int::ONE << (F::EXP_BITS - 1), - (F::Int::ONE << (F::EXP_BITS - 1)) + F::Int::ONE, - (F::Int::ONE << F::EXP_BITS) - F::Int::ONE, + 0, + 1, + 1 << (F::EXP_BITS / 2), + (1 << (F::EXP_BITS - 1)) - 1, + 1 << (F::EXP_BITS - 1), + (1 << (F::EXP_BITS - 1)) + 1, + (1 << F::EXP_BITS) - 1, ] .iter() { diff --git a/library/compiler-builtins/builtins-test/tests/addsub.rs b/library/compiler-builtins/builtins-test/tests/addsub.rs index 410967967d2a3..e19e5400e86a6 100644 --- a/library/compiler-builtins/builtins-test/tests/addsub.rs +++ b/library/compiler-builtins/builtins-test/tests/addsub.rs @@ -87,7 +87,8 @@ macro_rules! float_sum { #[test] fn $fn_add() { use core::ops::{Add, Sub}; - use compiler_builtins::float::{{add::$fn_add, sub::$fn_sub}, Float}; + use compiler_builtins::float::{add::$fn_add, sub::$fn_sub}; + use compiler_builtins::support::Float; fuzz_float_2(N, |x: $f, y: $f| { let add0 = apfloat_fallback!($f, $apfloat_ty, $sys_available, Add::add, x, y); diff --git a/library/compiler-builtins/builtins-test/tests/conv.rs b/library/compiler-builtins/builtins-test/tests/conv.rs index b94a2ce8de5f4..9d8dde52bac38 100644 --- a/library/compiler-builtins/builtins-test/tests/conv.rs +++ b/library/compiler-builtins/builtins-test/tests/conv.rs @@ -6,7 +6,7 @@ #![allow(unused_macros)] use builtins_test::*; -use compiler_builtins::float::Float; +use compiler_builtins::support::Float; use rustc_apfloat::{Float as _, FloatConvert as _}; mod i_to_f { @@ -259,7 +259,8 @@ macro_rules! f_to_f { ) => {$( #[test] fn $fn() { - use compiler_builtins::float::{$mod::$fn, Float}; + use compiler_builtins::float::$mod::$fn; + use compiler_builtins::support::Float; use rustc_apfloat::ieee::{$from_ap_ty, $to_ap_ty}; fuzz_float(N, |x: $from_ty| { diff --git a/library/compiler-builtins/builtins-test/tests/div_rem.rs b/library/compiler-builtins/builtins-test/tests/div_rem.rs index 4ff86385a9630..81d7470ba8736 100644 --- a/library/compiler-builtins/builtins-test/tests/div_rem.rs +++ b/library/compiler-builtins/builtins-test/tests/div_rem.rs @@ -109,7 +109,8 @@ macro_rules! float { $( #[test] fn $fn() { - use compiler_builtins::float::{div::$fn, Float}; + use compiler_builtins::float::div::$fn; + use compiler_builtins::support::Float; use core::ops::Div; fuzz_float_2(N, |x: $f, y: $f| { diff --git a/library/compiler-builtins/builtins-test/tests/float_pow.rs b/library/compiler-builtins/builtins-test/tests/float_pow.rs index 3cea83a255c8c..bce073a2342b7 100644 --- a/library/compiler-builtins/builtins-test/tests/float_pow.rs +++ b/library/compiler-builtins/builtins-test/tests/float_pow.rs @@ -16,7 +16,8 @@ macro_rules! pow { #[cfg($sys_available)] fn $fn() { use compiler_builtins::float::pow::$fn; - use compiler_builtins::float::Float; + use compiler_builtins::support::Float; + fuzz_float_2(N, |x: $f, y: $f| { if !(Float::is_subnormal(x) || Float::is_subnormal(y) || x.is_nan()) { let n = y.to_bits() & !<$f as Float>::SIG_MASK; diff --git a/library/compiler-builtins/builtins-test/tests/mul.rs b/library/compiler-builtins/builtins-test/tests/mul.rs index 30516ebaf7866..3af61fe0d2916 100644 --- a/library/compiler-builtins/builtins-test/tests/mul.rs +++ b/library/compiler-builtins/builtins-test/tests/mul.rs @@ -96,7 +96,8 @@ macro_rules! float_mul { $( #[test] fn $fn() { - use compiler_builtins::float::{mul::$fn, Float}; + use compiler_builtins::float::mul::$fn; + use compiler_builtins::support::Float; use core::ops::Mul; fuzz_float_2(N, |x: $f, y: $f| { diff --git a/library/compiler-builtins/compiler-builtins/src/float/add.rs b/library/compiler-builtins/compiler-builtins/src/float/add.rs index 88b2fc80d9d6c..69de07372f16e 100644 --- a/library/compiler-builtins/compiler-builtins/src/float/add.rs +++ b/library/compiler-builtins/compiler-builtins/src/float/add.rs @@ -1,5 +1,4 @@ -use crate::float::Float; -use crate::support::{CastFrom, CastInto, Int, MinInt}; +use crate::support::{CastFrom, CastInto, Float, Int, MinInt}; /// Returns `a + b` fn add(a: F, b: F) -> F diff --git a/library/compiler-builtins/compiler-builtins/src/float/cmp.rs b/library/compiler-builtins/compiler-builtins/src/float/cmp.rs index 88ff54535c6ce..60247fddb35df 100644 --- a/library/compiler-builtins/compiler-builtins/src/float/cmp.rs +++ b/library/compiler-builtins/compiler-builtins/src/float/cmp.rs @@ -1,7 +1,6 @@ #![allow(unreachable_code)] -use crate::float::Float; -use crate::support::{MinInt, cfg_if}; +use crate::support::{Float, MinInt, cfg_if}; // Taken from LLVM config [1], which should match GCC's `CMPtype` [2]. // diff --git a/library/compiler-builtins/compiler-builtins/src/float/conv.rs b/library/compiler-builtins/compiler-builtins/src/float/conv.rs index e6456a5f9f1a8..7310cd4ec4f02 100644 --- a/library/compiler-builtins/compiler-builtins/src/float/conv.rs +++ b/library/compiler-builtins/compiler-builtins/src/float/conv.rs @@ -1,7 +1,6 @@ use core::ops::Neg; -use super::Float; -use crate::support::{CastFrom, CastInto, Int, MinInt}; +use crate::support::{CastFrom, CastInto, Float, Int, MinInt}; /// Conversions from integers to floats. /// diff --git a/library/compiler-builtins/compiler-builtins/src/float/div.rs b/library/compiler-builtins/compiler-builtins/src/float/div.rs index 6f3939875a3ea..419d8ad5e7061 100644 --- a/library/compiler-builtins/compiler-builtins/src/float/div.rs +++ b/library/compiler-builtins/compiler-builtins/src/float/div.rs @@ -82,9 +82,7 @@ use core::mem::size_of; use core::ops; -use super::HalfRep; -use crate::float::Float; -use crate::support::{CastFrom, CastInto, DInt, HInt, Int, MinInt}; +use crate::support::{CastFrom, CastInto, DInt, Float, HInt, HalfRep, Int, MinInt}; fn div(a: F, b: F) -> F where diff --git a/library/compiler-builtins/compiler-builtins/src/float/extend.rs b/library/compiler-builtins/compiler-builtins/src/float/extend.rs index 02cd743d14ebe..58038ce57f834 100644 --- a/library/compiler-builtins/compiler-builtins/src/float/extend.rs +++ b/library/compiler-builtins/compiler-builtins/src/float/extend.rs @@ -1,5 +1,4 @@ -use crate::float::Float; -use crate::support::{CastInto, Int, MinInt}; +use crate::support::{CastInto, Float, Int, MinInt}; /// Generic conversion from a narrower to a wider IEEE-754 floating-point type fn extend(a: F) -> R diff --git a/library/compiler-builtins/compiler-builtins/src/float/mod.rs b/library/compiler-builtins/compiler-builtins/src/float/mod.rs index 4a379d0d3575b..15318c4928804 100644 --- a/library/compiler-builtins/compiler-builtins/src/float/mod.rs +++ b/library/compiler-builtins/compiler-builtins/src/float/mod.rs @@ -6,10 +6,4 @@ pub mod extend; pub mod mul; pub mod pow; pub mod sub; -pub(crate) mod traits; pub mod trunc; - -#[cfg(not(feature = "unstable-public-internals"))] -pub(crate) use traits::{Float, HalfRep}; -#[cfg(feature = "unstable-public-internals")] -pub use traits::{Float, HalfRep}; diff --git a/library/compiler-builtins/compiler-builtins/src/float/mul.rs b/library/compiler-builtins/compiler-builtins/src/float/mul.rs index 7fb57ce702574..ffba2dc41f8a0 100644 --- a/library/compiler-builtins/compiler-builtins/src/float/mul.rs +++ b/library/compiler-builtins/compiler-builtins/src/float/mul.rs @@ -1,5 +1,4 @@ -use crate::float::Float; -use crate::support::{CastInto, DInt, HInt, Int, MinInt}; +use crate::support::{CastInto, DInt, Float, HInt, Int, MinInt}; fn mul(a: F, b: F) -> F where diff --git a/library/compiler-builtins/compiler-builtins/src/float/pow.rs b/library/compiler-builtins/compiler-builtins/src/float/pow.rs index 4c58301fff33f..2c92971d31397 100644 --- a/library/compiler-builtins/compiler-builtins/src/float/pow.rs +++ b/library/compiler-builtins/compiler-builtins/src/float/pow.rs @@ -1,5 +1,4 @@ -use crate::float::Float; -use crate::support::Int; +use crate::support::{Float, Int}; /// Returns `a` raised to the power `b` fn pow(a: F, b: i32) -> F { diff --git a/library/compiler-builtins/compiler-builtins/src/float/sub.rs b/library/compiler-builtins/compiler-builtins/src/float/sub.rs index 48ef33b0b826f..11dd3b77d5d1c 100644 --- a/library/compiler-builtins/compiler-builtins/src/float/sub.rs +++ b/library/compiler-builtins/compiler-builtins/src/float/sub.rs @@ -1,4 +1,4 @@ -use crate::float::Float; +use crate::support::Float; intrinsics! { #[cfg(f16_enabled)] diff --git a/library/compiler-builtins/compiler-builtins/src/float/traits.rs b/library/compiler-builtins/compiler-builtins/src/float/traits.rs deleted file mode 100644 index 8bea3e900ddae..0000000000000 --- a/library/compiler-builtins/compiler-builtins/src/float/traits.rs +++ /dev/null @@ -1,189 +0,0 @@ -use core::ops; - -use crate::support::{DInt, Int, MinInt}; - -/// Wrapper to extract the integer type half of the float's size -pub type HalfRep = <::Int as DInt>::H; - -/// Trait for some basic operations on floats -#[allow(dead_code)] -pub trait Float: - Copy - + core::fmt::Debug - + PartialEq - + PartialOrd - + ops::AddAssign - + ops::MulAssign - + ops::Add - + ops::Sub - + ops::Div - + ops::Rem -{ - /// A uint of the same width as the float - type Int: Int; - - /// A int of the same width as the float - type SignedInt: Int + MinInt; - - /// An int capable of containing the exponent bits plus a sign bit. This is signed. - type ExpInt: Int; - - const ZERO: Self; - const ONE: Self; - - /// The bitwidth of the float type. - const BITS: u32; - - /// The bitwidth of the significand. - const SIG_BITS: u32; - - /// The bitwidth of the exponent. - const EXP_BITS: u32 = Self::BITS - Self::SIG_BITS - 1; - - /// The saturated (maximum bitpattern) value of the exponent, i.e. the infinite - /// representation. - /// - /// This is in the rightmost position, use `EXP_MASK` for the shifted value. - const EXP_SAT: u32 = (1 << Self::EXP_BITS) - 1; - - /// The exponent bias value. - const EXP_BIAS: u32 = Self::EXP_SAT >> 1; - - /// A mask for the sign bit. - const SIGN_MASK: Self::Int; - - /// A mask for the significand. - const SIG_MASK: Self::Int; - - /// The implicit bit of the float format. - const IMPLICIT_BIT: Self::Int; - - /// A mask for the exponent. - const EXP_MASK: Self::Int; - - /// Returns `self` transmuted to `Self::Int` - fn to_bits(self) -> Self::Int; - - /// Returns `self` transmuted to `Self::SignedInt` - fn to_bits_signed(self) -> Self::SignedInt; - - /// Checks if two floats have the same bit representation. *Except* for NaNs! NaN can be - /// represented in multiple different ways. This method returns `true` if two NaNs are - /// compared. - fn eq_repr(self, rhs: Self) -> bool; - - /// Returns true if the sign is negative - fn is_sign_negative(self) -> bool; - - /// Returns the exponent, not adjusting for bias. - fn exp(self) -> Self::ExpInt; - - /// Returns the significand with no implicit bit (or the "fractional" part) - fn frac(self) -> Self::Int; - - /// Returns the significand with implicit bit - fn imp_frac(self) -> Self::Int; - - /// Returns a `Self::Int` transmuted back to `Self` - fn from_bits(a: Self::Int) -> Self; - - /// Constructs a `Self` from its parts. Inputs are treated as bits and shifted into position. - fn from_parts(negative: bool, exponent: Self::Int, significand: Self::Int) -> Self; - - fn abs(self) -> Self { - let abs_mask = !Self::SIGN_MASK; - Self::from_bits(self.to_bits() & abs_mask) - } - - /// Returns (normalized exponent, normalized significand) - fn normalize(significand: Self::Int) -> (i32, Self::Int); - - /// Returns if `self` is subnormal - fn is_subnormal(self) -> bool; -} - -macro_rules! float_impl { - ($ty:ident, $ity:ident, $sity:ident, $expty:ident, $bits:expr, $significand_bits:expr) => { - impl Float for $ty { - type Int = $ity; - type SignedInt = $sity; - type ExpInt = $expty; - - const ZERO: Self = 0.0; - const ONE: Self = 1.0; - - const BITS: u32 = $bits; - const SIG_BITS: u32 = $significand_bits; - - const SIGN_MASK: Self::Int = 1 << (Self::BITS - 1); - const SIG_MASK: Self::Int = (1 << Self::SIG_BITS) - 1; - const IMPLICIT_BIT: Self::Int = 1 << Self::SIG_BITS; - const EXP_MASK: Self::Int = !(Self::SIGN_MASK | Self::SIG_MASK); - - fn to_bits(self) -> Self::Int { - self.to_bits() - } - fn to_bits_signed(self) -> Self::SignedInt { - self.to_bits() as Self::SignedInt - } - fn eq_repr(self, rhs: Self) -> bool { - #[cfg(feature = "mangled-names")] - fn is_nan(x: $ty) -> bool { - // When using mangled-names, the "real" compiler-builtins might not have the - // necessary builtin (__unordtf2) to test whether `f128` is NaN. - // FIXME(f16_f128): Remove once the nightly toolchain has the __unordtf2 builtin - // x is NaN if all the bits of the exponent are set and the significand is non-0 - x.to_bits() & $ty::EXP_MASK == $ty::EXP_MASK && x.to_bits() & $ty::SIG_MASK != 0 - } - #[cfg(not(feature = "mangled-names"))] - fn is_nan(x: $ty) -> bool { - x.is_nan() - } - if is_nan(self) && is_nan(rhs) { - true - } else { - self.to_bits() == rhs.to_bits() - } - } - fn is_sign_negative(self) -> bool { - self.is_sign_negative() - } - fn exp(self) -> Self::ExpInt { - ((self.to_bits() & Self::EXP_MASK) >> Self::SIG_BITS) as Self::ExpInt - } - fn frac(self) -> Self::Int { - self.to_bits() & Self::SIG_MASK - } - fn imp_frac(self) -> Self::Int { - self.frac() | Self::IMPLICIT_BIT - } - fn from_bits(a: Self::Int) -> Self { - Self::from_bits(a) - } - fn from_parts(negative: bool, exponent: Self::Int, significand: Self::Int) -> Self { - Self::from_bits( - ((negative as Self::Int) << (Self::BITS - 1)) - | ((exponent << Self::SIG_BITS) & Self::EXP_MASK) - | (significand & Self::SIG_MASK), - ) - } - fn normalize(significand: Self::Int) -> (i32, Self::Int) { - let shift = significand.leading_zeros().wrapping_sub(Self::EXP_BITS); - ( - 1i32.wrapping_sub(shift as i32), - significand << shift as Self::Int, - ) - } - fn is_subnormal(self) -> bool { - (self.to_bits() & Self::EXP_MASK) == Self::Int::ZERO - } - } - }; -} - -#[cfg(f16_enabled)] -float_impl!(f16, u16, i16, i8, 16, 10); -float_impl!(f32, u32, i32, i16, 32, 23); -float_impl!(f64, u64, i64, i16, 64, 52); -#[cfg(f128_enabled)] -float_impl!(f128, u128, i128, i16, 128, 112); diff --git a/library/compiler-builtins/compiler-builtins/src/float/trunc.rs b/library/compiler-builtins/compiler-builtins/src/float/trunc.rs index a3f578d0f723e..1a88b0649fda3 100644 --- a/library/compiler-builtins/compiler-builtins/src/float/trunc.rs +++ b/library/compiler-builtins/compiler-builtins/src/float/trunc.rs @@ -1,5 +1,4 @@ -use crate::float::Float; -use crate::support::{CastInto, Int, MinInt}; +use crate::support::{CastInto, Float, Int, MinInt}; fn trunc(a: F) -> R where diff --git a/library/compiler-builtins/libm-test/src/f8_impl.rs b/library/compiler-builtins/libm-test/src/f8_impl.rs index 9f19f518e2a34..3288e6a6acf2c 100644 --- a/library/compiler-builtins/libm-test/src/f8_impl.rs +++ b/library/compiler-builtins/libm-test/src/f8_impl.rs @@ -58,6 +58,14 @@ impl Float for f8 { self.0 as i8 } + fn eq_repr(self, rhs: Self) -> bool { + if self.is_nan() && rhs.is_nan() { + true + } else { + self.to_bits() == rhs.to_bits() + } + } + fn is_nan(self) -> bool { self.0 & Self::EXP_MASK == Self::EXP_MASK && self.0 & Self::SIG_MASK != 0 } diff --git a/library/compiler-builtins/libm/Cargo.toml b/library/compiler-builtins/libm/Cargo.toml index 28e594dca1f91..f87e7a4282415 100644 --- a/library/compiler-builtins/libm/Cargo.toml +++ b/library/compiler-builtins/libm/Cargo.toml @@ -48,6 +48,7 @@ force-soft-floats = [] [lints.rust] unexpected_cfgs = { level = "warn", check-cfg = [ - # compiler-builtins sets this feature, but we use it in `libm` + # compiler-builtins sets these features, but we use them in `libm` 'cfg(feature, values("compiler-builtins"))', + 'cfg(feature, values("mangled-names"))', ] } diff --git a/library/compiler-builtins/libm/src/math/support/float_traits.rs b/library/compiler-builtins/libm/src/math/support/float_traits.rs index b1b86552f3519..55ffadea0f7f7 100644 --- a/library/compiler-builtins/libm/src/math/support/float_traits.rs +++ b/library/compiler-builtins/libm/src/math/support/float_traits.rs @@ -1,7 +1,11 @@ use core::{fmt, mem, ops}; use super::int_traits::{CastFrom, Int, MinInt}; -use crate::support::DisplayHex; +use crate::support::{DInt, DisplayHex}; + +/// Wrapper to extract the integer type half of the float's size +#[allow(unused)] // only used in c-b +pub type HalfRep = <::Int as DInt>::H; /// Whether MIPS sNaN/qNaNs should be used. /// @@ -122,13 +126,7 @@ pub trait Float: /// This method returns `true` if two NaNs are compared. Use [`biteq`](Self::biteq) instead /// if `NaN` should not be treated separately. #[allow(dead_code)] - fn eq_repr(self, rhs: Self) -> bool { - if self.is_nan() && rhs.is_nan() { - true - } else { - self.biteq(rhs) - } - } + fn eq_repr(self, rhs: Self) -> bool; /// Returns true if the value is NaN. fn is_nan(self) -> bool; @@ -301,6 +299,27 @@ macro_rules! float_impl { fn to_bits(self) -> Self::Int { self.to_bits() } + + fn eq_repr(self, rhs: Self) -> bool { + #[cfg(feature = "mangled-names")] + fn is_nan(x: $ty) -> bool { + // When using mangled-names, the "real" compiler-builtins might not have the + // necessary builtin (__unordtf2) to test whether `f128` is NaN. + // FIXME(f128): Remove once the nightly toolchain has the __unordtf2 builtin + // x is NaN if all the bits of the exponent are set and the significand is non-0 + x.to_bits() & $ty::EXP_MASK == $ty::EXP_MASK && x.to_bits() & $ty::SIG_MASK != 0 + } + #[cfg(not(feature = "mangled-names"))] + fn is_nan(x: $ty) -> bool { + x.is_nan() + } + if is_nan(self) && is_nan(rhs) { + true + } else { + self.to_bits() == rhs.to_bits() + } + } + fn is_nan(self) -> bool { self.is_nan() } diff --git a/library/compiler-builtins/libm/src/math/support/mod.rs b/library/compiler-builtins/libm/src/math/support/mod.rs index b8269fc212ce0..f28c021040da7 100644 --- a/library/compiler-builtins/libm/src/math/support/mod.rs +++ b/library/compiler-builtins/libm/src/math/support/mod.rs @@ -17,7 +17,7 @@ pub use big::{i256, u256}; pub(crate) use cfg_if; pub use env::{FpResult, Round, Status}; #[allow(unused_imports)] -pub use float_traits::{DFloat, Float, HFloat, IntTy}; +pub use float_traits::{DFloat, Float, HFloat, HalfRep, IntTy}; pub(crate) use float_traits::{f32_from_bits, f64_from_bits}; #[cfg(f16_enabled)] #[allow(unused_imports)] From 4247543c4fdd8ddceb10bca8ca8215681dd862ff Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Mon, 30 Mar 2026 02:33:45 -0500 Subject: [PATCH 054/183] libm: Add status output support to `rint_status` Rename `rint_round` to `rint_status` since its rounding argument is not being used, and add support for returning the status. --- .../libm/src/math/generic/mod.rs | 2 +- .../libm/src/math/generic/rint.rs | 11 ++- .../compiler-builtins/libm/src/math/rint.rs | 95 +++++++++++++++++- .../libm/src/math/roundeven.rs | 99 ++----------------- 4 files changed, 107 insertions(+), 100 deletions(-) diff --git a/library/compiler-builtins/libm/src/math/generic/mod.rs b/library/compiler-builtins/libm/src/math/generic/mod.rs index b54e0a15fecf2..7a26295e39077 100644 --- a/library/compiler-builtins/libm/src/math/generic/mod.rs +++ b/library/compiler-builtins/libm/src/math/generic/mod.rs @@ -45,7 +45,7 @@ pub use fminimum_num::fminimum_num; pub use fmod::fmod; pub use frexp::frexp; pub use ilogb::ilogb; -pub use rint::rint_round; +pub use rint::rint_status; pub use round::round; pub use scalbn::scalbn; #[cfg(test)] diff --git a/library/compiler-builtins/libm/src/math/generic/rint.rs b/library/compiler-builtins/libm/src/math/generic/rint.rs index 76f625f3376e1..fb0d68249a3e5 100644 --- a/library/compiler-builtins/libm/src/math/generic/rint.rs +++ b/library/compiler-builtins/libm/src/math/generic/rint.rs @@ -1,12 +1,12 @@ /* SPDX-License-Identifier: MIT */ /* origin: musl src/math/rint.c */ -use crate::support::{Float, FpResult, Round}; +use crate::support::{Float, FpResult, Status}; /// IEEE 754-2019 `roundToIntegralExact`, which respects rounding mode and raises inexact if /// applicable. #[inline] -pub fn rint_round(x: F, _round: Round) -> FpResult { +pub fn rint_status(x: F) -> FpResult { let toint = F::ONE / F::EPSILON; let e = x.ex(); let positive = x.is_sign_positive(); @@ -41,5 +41,10 @@ pub fn rint_round(x: F, _round: Round) -> FpResult { } }; - FpResult::ok(res) + let status = if res == x { + Status::OK + } else { + Status::INEXACT + }; + FpResult::new(res, status) } diff --git a/library/compiler-builtins/libm/src/math/rint.rs b/library/compiler-builtins/libm/src/math/rint.rs index 011a7ae3d60ad..3cfbfb8d6d571 100644 --- a/library/compiler-builtins/libm/src/math/rint.rs +++ b/library/compiler-builtins/libm/src/math/rint.rs @@ -1,4 +1,4 @@ -use super::support::Round; +use super::generic; /// Round `x` to the nearest integer, breaking ties toward even. #[cfg(f16_enabled)] @@ -10,7 +10,7 @@ pub fn rintf16(x: f16) -> f16 { args: x, } - super::generic::rint_round(x, Round::Nearest).val + generic::rint_status(x).val } /// Round `x` to the nearest integer, breaking ties toward even. @@ -25,7 +25,7 @@ pub fn rintf(x: f32) -> f32 { args: x, } - super::generic::rint_round(x, Round::Nearest).val + generic::rint_status(x).val } /// Round `x` to the nearest integer, breaking ties toward even. @@ -40,12 +40,97 @@ pub fn rint(x: f64) -> f64 { args: x, } - super::generic::rint_round(x, Round::Nearest).val + generic::rint_status(x).val } /// Round `x` to the nearest integer, breaking ties toward even. #[cfg(f128_enabled)] #[cfg_attr(assert_no_panic, no_panic::no_panic)] pub fn rintf128(x: f128) -> f128 { - super::generic::rint_round(x, Round::Nearest).val + generic::rint_status(x).val +} + +#[cfg(test)] +mod tests { + use super::*; + use crate::support::{Float, FpResult, Hex, Status}; + + fn spec_test(cases: &[(F, F, Status)]) { + let roundtrip = [ + F::ZERO, + F::ONE, + F::NEG_ONE, + F::NEG_ZERO, + F::INFINITY, + F::NEG_INFINITY, + ]; + + for x in roundtrip { + let FpResult { val, status } = generic::rint_status(x); + assert_biteq!(val, x, "rint_status({})", Hex(x)); + assert_eq!(status, Status::OK, "{}", Hex(x)); + } + + for &(x, res, res_stat) in cases { + let FpResult { val, status } = generic::rint_status(x); + assert_biteq!(val, res, "rint_status({})", Hex(x)); + assert_eq!(status, res_stat, "{}", Hex(x)); + } + } + + #[test] + #[cfg(f16_enabled)] + fn spec_tests_f16() { + let cases = []; + spec_test::(&cases); + } + + #[test] + fn spec_tests_f32() { + let cases = [ + (0.1, 0.0, Status::INEXACT), + (-0.1, -0.0, Status::INEXACT), + (0.5, 0.0, Status::INEXACT), + (-0.5, -0.0, Status::INEXACT), + (0.9, 1.0, Status::INEXACT), + (-0.9, -1.0, Status::INEXACT), + (1.1, 1.0, Status::INEXACT), + (-1.1, -1.0, Status::INEXACT), + (1.5, 2.0, Status::INEXACT), + (-1.5, -2.0, Status::INEXACT), + (1.9, 2.0, Status::INEXACT), + (-1.9, -2.0, Status::INEXACT), + (2.8, 3.0, Status::INEXACT), + (-2.8, -3.0, Status::INEXACT), + ]; + spec_test::(&cases); + } + + #[test] + fn spec_tests_f64() { + let cases = [ + (0.1, 0.0, Status::INEXACT), + (-0.1, -0.0, Status::INEXACT), + (0.5, 0.0, Status::INEXACT), + (-0.5, -0.0, Status::INEXACT), + (0.9, 1.0, Status::INEXACT), + (-0.9, -1.0, Status::INEXACT), + (1.1, 1.0, Status::INEXACT), + (-1.1, -1.0, Status::INEXACT), + (1.5, 2.0, Status::INEXACT), + (-1.5, -2.0, Status::INEXACT), + (1.9, 2.0, Status::INEXACT), + (-1.9, -2.0, Status::INEXACT), + (2.8, 3.0, Status::INEXACT), + (-2.8, -3.0, Status::INEXACT), + ]; + spec_test::(&cases); + } + + #[test] + #[cfg(f128_enabled)] + fn spec_tests_f128() { + let cases = []; + spec_test::(&cases); + } } diff --git a/library/compiler-builtins/libm/src/math/roundeven.rs b/library/compiler-builtins/libm/src/math/roundeven.rs index ec47c8074efa9..4cedd0c16b82d 100644 --- a/library/compiler-builtins/libm/src/math/roundeven.rs +++ b/library/compiler-builtins/libm/src/math/roundeven.rs @@ -1,26 +1,28 @@ -use super::generic; -use super::support::Round; +//! Note that we can use `rint` for these implementations since Rust expects the rounding +//! mode is always ties-to-even. `roundeven` also does not raise `FE_INEXACT`. +//! +//! Tested in the `rint` module. /// Round `x` to the nearest integer, breaking ties toward even. This is IEEE 754 /// `roundToIntegralTiesToEven`. #[cfg(f16_enabled)] #[cfg_attr(assert_no_panic, no_panic::no_panic)] pub fn roundevenf16(x: f16) -> f16 { - generic::rint_round(x, Round::Nearest).val + super::rintf16(x) } /// Round `x` to the nearest integer, breaking ties toward even. This is IEEE 754 /// `roundToIntegralTiesToEven`. #[cfg_attr(assert_no_panic, no_panic::no_panic)] pub fn roundevenf(x: f32) -> f32 { - generic::rint_round(x, Round::Nearest).val + super::rintf(x) } /// Round `x` to the nearest integer, breaking ties toward even. This is IEEE 754 /// `roundToIntegralTiesToEven`. #[cfg_attr(assert_no_panic, no_panic::no_panic)] pub fn roundeven(x: f64) -> f64 { - generic::rint_round(x, Round::Nearest).val + super::rint(x) } /// Round `x` to the nearest integer, breaking ties toward even. This is IEEE 754 @@ -28,90 +30,5 @@ pub fn roundeven(x: f64) -> f64 { #[cfg(f128_enabled)] #[cfg_attr(assert_no_panic, no_panic::no_panic)] pub fn roundevenf128(x: f128) -> f128 { - generic::rint_round(x, Round::Nearest).val -} - -#[cfg(test)] -mod tests { - use super::*; - use crate::support::{Float, FpResult, Hex, Status}; - - fn spec_test(cases: &[(F, F, Status)]) { - let roundtrip = [ - F::ZERO, - F::ONE, - F::NEG_ONE, - F::NEG_ZERO, - F::INFINITY, - F::NEG_INFINITY, - ]; - - for x in roundtrip { - let FpResult { val, status } = generic::rint_round(x, Round::Nearest); - assert_biteq!(val, x, "rint_round({})", Hex(x)); - assert_eq!(status, Status::OK, "{}", Hex(x)); - } - - for &(x, res, res_stat) in cases { - let FpResult { val, status } = generic::rint_round(x, Round::Nearest); - assert_biteq!(val, res, "rint_round({})", Hex(x)); - assert_eq!(status, res_stat, "{}", Hex(x)); - } - } - - #[test] - #[cfg(f16_enabled)] - fn spec_tests_f16() { - let cases = []; - spec_test::(&cases); - } - - #[test] - fn spec_tests_f32() { - let cases = [ - (0.1, 0.0, Status::OK), - (-0.1, -0.0, Status::OK), - (0.5, 0.0, Status::OK), - (-0.5, -0.0, Status::OK), - (0.9, 1.0, Status::OK), - (-0.9, -1.0, Status::OK), - (1.1, 1.0, Status::OK), - (-1.1, -1.0, Status::OK), - (1.5, 2.0, Status::OK), - (-1.5, -2.0, Status::OK), - (1.9, 2.0, Status::OK), - (-1.9, -2.0, Status::OK), - (2.8, 3.0, Status::OK), - (-2.8, -3.0, Status::OK), - ]; - spec_test::(&cases); - } - - #[test] - fn spec_tests_f64() { - let cases = [ - (0.1, 0.0, Status::OK), - (-0.1, -0.0, Status::OK), - (0.5, 0.0, Status::OK), - (-0.5, -0.0, Status::OK), - (0.9, 1.0, Status::OK), - (-0.9, -1.0, Status::OK), - (1.1, 1.0, Status::OK), - (-1.1, -1.0, Status::OK), - (1.5, 2.0, Status::OK), - (-1.5, -2.0, Status::OK), - (1.9, 2.0, Status::OK), - (-1.9, -2.0, Status::OK), - (2.8, 3.0, Status::OK), - (-2.8, -3.0, Status::OK), - ]; - spec_test::(&cases); - } - - #[test] - #[cfg(f128_enabled)] - fn spec_tests_f128() { - let cases = []; - spec_test::(&cases); - } + super::rintf128(x) } From bfb6050ebd71eb1c0696bca3b86d986a67c18289 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Mon, 30 Mar 2026 02:33:45 -0500 Subject: [PATCH 055/183] libm: Make unit test setup consistent across rounding functions --- .../compiler-builtins/libm/src/math/ceil.rs | 4 +- .../compiler-builtins/libm/src/math/floor.rs | 4 +- .../compiler-builtins/libm/src/math/rint.rs | 125 +++++++++--------- .../compiler-builtins/libm/src/math/round.rs | 108 ++++++++------- .../compiler-builtins/libm/src/math/trunc.rs | 4 +- 5 files changed, 128 insertions(+), 117 deletions(-) diff --git a/library/compiler-builtins/libm/src/math/ceil.rs b/library/compiler-builtins/libm/src/math/ceil.rs index 68da1f59228a5..4dc2e175ac459 100644 --- a/library/compiler-builtins/libm/src/math/ceil.rs +++ b/library/compiler-builtins/libm/src/math/ceil.rs @@ -83,7 +83,7 @@ mod tests { fn check(cases: &[(F, F, Status)]) { for &(x, exp_res, exp_stat) in cases { let FpResult { val, status } = generic::ceil_status(x); - assert_biteq!(val, exp_res, "{x:?} {}", Hex(x)); + assert_biteq!(val, exp_res, "ceil({x:?}) ({})", Hex(x)); assert_eq!( status, exp_stat, @@ -124,7 +124,7 @@ mod tests { #[test] #[cfg(f128_enabled)] - fn spec_tests_f128() { + fn check_f128() { check::(&cases!(f128)); check::(&[ (hf128!("0x1p112"), hf128!("0x1p112"), Status::OK), diff --git a/library/compiler-builtins/libm/src/math/floor.rs b/library/compiler-builtins/libm/src/math/floor.rs index f8bbc4b26ce66..d6bd2113b047b 100644 --- a/library/compiler-builtins/libm/src/math/floor.rs +++ b/library/compiler-builtins/libm/src/math/floor.rs @@ -83,7 +83,7 @@ mod tests { fn check(cases: &[(F, F, Status)]) { for &(x, exp_res, exp_stat) in cases { let FpResult { val, status } = generic::floor_status(x); - assert_biteq!(val, exp_res, "{x:?} {}", Hex(x)); + assert_biteq!(val, exp_res, "floor({x:?}) ({})", Hex(x)); assert_eq!( status, exp_stat, @@ -124,7 +124,7 @@ mod tests { #[test] #[cfg(f128_enabled)] - fn spec_tests_f128() { + fn check_f128() { check::(&cases!(f128)); check::(&[ (hf128!("0x1p112"), hf128!("0x1p112"), Status::OK), diff --git a/library/compiler-builtins/libm/src/math/rint.rs b/library/compiler-builtins/libm/src/math/rint.rs index 3cfbfb8d6d571..b46de6beaac50 100644 --- a/library/compiler-builtins/libm/src/math/rint.rs +++ b/library/compiler-builtins/libm/src/math/rint.rs @@ -55,82 +55,87 @@ mod tests { use super::*; use crate::support::{Float, FpResult, Hex, Status}; - fn spec_test(cases: &[(F, F, Status)]) { - let roundtrip = [ - F::ZERO, - F::ONE, - F::NEG_ONE, - F::NEG_ZERO, - F::INFINITY, - F::NEG_INFINITY, - ]; - - for x in roundtrip { - let FpResult { val, status } = generic::rint_status(x); - assert_biteq!(val, x, "rint_status({})", Hex(x)); - assert_eq!(status, Status::OK, "{}", Hex(x)); - } + macro_rules! cases { + ($f:ty) => { + [ + // roundtrip + (0.0, 0.0, Status::OK), + (-0.0, -0.0, Status::OK), + (1.0, 1.0, Status::OK), + (-1.0, -1.0, Status::OK), + (<$f>::INFINITY, <$f>::INFINITY, Status::OK), + (<$f>::NEG_INFINITY, <$f>::NEG_INFINITY, Status::OK), + // with rounding + (0.1, 0.0, Status::INEXACT), + (-0.1, -0.0, Status::INEXACT), + (0.5, 0.0, Status::INEXACT), + (-0.5, -0.0, Status::INEXACT), + (0.9, 1.0, Status::INEXACT), + (-0.9, -1.0, Status::INEXACT), + (1.1, 1.0, Status::INEXACT), + (-1.1, -1.0, Status::INEXACT), + (1.5, 2.0, Status::INEXACT), + (-1.5, -2.0, Status::INEXACT), + (1.9, 2.0, Status::INEXACT), + (-1.9, -2.0, Status::INEXACT), + (2.5, 2.0, Status::INEXACT), + (-2.5, -2.0, Status::INEXACT), + (3.5, 4.0, Status::INEXACT), + (-3.5, -4.0, Status::INEXACT), + ] + }; + } - for &(x, res, res_stat) in cases { + #[track_caller] + fn check(cases: &[(F, F, Status)]) { + for &(x, exp_res, exp_stat) in cases { let FpResult { val, status } = generic::rint_status(x); - assert_biteq!(val, res, "rint_status({})", Hex(x)); - assert_eq!(status, res_stat, "{}", Hex(x)); + assert_biteq!(val, exp_res, "roundeven({x:?}) ({})", Hex(x)); + assert_eq!( + status, + exp_stat, + "{x:?} {} -> {exp_res:?} {}", + Hex(x), + Hex(exp_res) + ); } } #[test] #[cfg(f16_enabled)] - fn spec_tests_f16() { - let cases = []; - spec_test::(&cases); + fn check_f16() { + check::(&cases!(f16)); + check::(&[ + (hf16!("0x1p10"), hf16!("0x1p10"), Status::OK), + (hf16!("-0x1p10"), hf16!("-0x1p10"), Status::OK), + ]); } #[test] - fn spec_tests_f32() { - let cases = [ - (0.1, 0.0, Status::INEXACT), - (-0.1, -0.0, Status::INEXACT), - (0.5, 0.0, Status::INEXACT), - (-0.5, -0.0, Status::INEXACT), - (0.9, 1.0, Status::INEXACT), - (-0.9, -1.0, Status::INEXACT), - (1.1, 1.0, Status::INEXACT), - (-1.1, -1.0, Status::INEXACT), - (1.5, 2.0, Status::INEXACT), - (-1.5, -2.0, Status::INEXACT), - (1.9, 2.0, Status::INEXACT), - (-1.9, -2.0, Status::INEXACT), - (2.8, 3.0, Status::INEXACT), - (-2.8, -3.0, Status::INEXACT), - ]; - spec_test::(&cases); + fn check_f32() { + check::(&cases!(f32)); + check::(&[ + (hf32!("0x1p23"), hf32!("0x1p23"), Status::OK), + (hf32!("-0x1p23"), hf32!("-0x1p23"), Status::OK), + ]); } #[test] - fn spec_tests_f64() { - let cases = [ - (0.1, 0.0, Status::INEXACT), - (-0.1, -0.0, Status::INEXACT), - (0.5, 0.0, Status::INEXACT), - (-0.5, -0.0, Status::INEXACT), - (0.9, 1.0, Status::INEXACT), - (-0.9, -1.0, Status::INEXACT), - (1.1, 1.0, Status::INEXACT), - (-1.1, -1.0, Status::INEXACT), - (1.5, 2.0, Status::INEXACT), - (-1.5, -2.0, Status::INEXACT), - (1.9, 2.0, Status::INEXACT), - (-1.9, -2.0, Status::INEXACT), - (2.8, 3.0, Status::INEXACT), - (-2.8, -3.0, Status::INEXACT), - ]; - spec_test::(&cases); + fn check_f64() { + check::(&cases!(f64)); + check::(&[ + (hf64!("0x1p52"), hf64!("0x1p52"), Status::OK), + (hf64!("-0x1p52"), hf64!("-0x1p52"), Status::OK), + ]); } #[test] #[cfg(f128_enabled)] - fn spec_tests_f128() { - let cases = []; - spec_test::(&cases); + fn check_f128() { + check::(&cases!(f128)); + check::(&[ + (hf128!("0x1p112"), hf128!("0x1p112"), Status::OK), + (hf128!("-0x1p112"), hf128!("-0x1p112"), Status::OK), + ]); } } diff --git a/library/compiler-builtins/libm/src/math/round.rs b/library/compiler-builtins/libm/src/math/round.rs index 204ffaf413f67..34afa375bb31c 100644 --- a/library/compiler-builtins/libm/src/math/round.rs +++ b/library/compiler-builtins/libm/src/math/round.rs @@ -29,72 +29,78 @@ pub fn roundf128(x: f128) -> f128 { #[cfg(test)] mod tests { use super::*; + use crate::support::{Float, Hex}; - #[test] - #[cfg(f16_enabled)] - fn zeroes_f16() { - assert_biteq!(generic::round(0.0_f16), 0.0_f16); - assert_biteq!(generic::round(-0.0_f16), -0.0_f16); - } - - #[test] - #[cfg(f16_enabled)] - fn sanity_check_f16() { - assert_eq!(generic::round(-1.0_f16), -1.0); - assert_eq!(generic::round(2.8_f16), 3.0); - assert_eq!(generic::round(-0.5_f16), -1.0); - assert_eq!(generic::round(0.5_f16), 1.0); - assert_eq!(generic::round(-1.5_f16), -2.0); - assert_eq!(generic::round(1.5_f16), 2.0); + macro_rules! cases { + ($f:ty) => { + [ + // roundtrip + (0.0, 0.0), + (-0.0, -0.0), + (1.0, 1.0), + (-1.0, -1.0), + (<$f>::INFINITY, <$f>::INFINITY), + (<$f>::NEG_INFINITY, <$f>::NEG_INFINITY), + // with rounding + (0.1, 0.0), + (-0.1, -0.0), + (0.5, 1.0), + (-0.5, -1.0), + (0.9, 1.0), + (-0.9, -1.0), + (1.1, 1.0), + (-1.1, -1.0), + (1.5, 2.0), + (-1.5, -2.0), + (1.9, 2.0), + (-1.9, -2.0), + ] + }; } - #[test] - fn zeroes_f32() { - assert_biteq!(generic::round(0.0_f32), 0.0_f32); - assert_biteq!(generic::round(-0.0_f32), -0.0_f32); - } - - #[test] - fn sanity_check_f32() { - assert_eq!(generic::round(-1.0_f32), -1.0); - assert_eq!(generic::round(2.8_f32), 3.0); - assert_eq!(generic::round(-0.5_f32), -1.0); - assert_eq!(generic::round(0.5_f32), 1.0); - assert_eq!(generic::round(-1.5_f32), -2.0); - assert_eq!(generic::round(1.5_f32), 2.0); + #[track_caller] + fn check(cases: &[(F, F)]) { + for &(x, exp_res) in cases { + let val = generic::round(x); + assert_biteq!(val, exp_res, "round({x:?}) {}", Hex(x)); + } } #[test] - fn zeroes_f64() { - assert_biteq!(generic::round(0.0_f64), 0.0_f64); - assert_biteq!(generic::round(-0.0_f64), -0.0_f64); + #[cfg(f16_enabled)] + fn check_f16() { + check::(&cases!(f16)); + check::(&[ + (hf16!("0x1p10"), hf16!("0x1p10")), + (hf16!("-0x1p10"), hf16!("-0x1p10")), + ]); } #[test] - fn sanity_check_f64() { - assert_eq!(generic::round(-1.0_f64), -1.0); - assert_eq!(generic::round(2.8_f64), 3.0); - assert_eq!(generic::round(-0.5_f64), -1.0); - assert_eq!(generic::round(0.5_f64), 1.0); - assert_eq!(generic::round(-1.5_f64), -2.0); - assert_eq!(generic::round(1.5_f64), 2.0); + fn check_f32() { + check::(&cases!(f32)); + check::(&[ + (hf32!("0x1p23"), hf32!("0x1p23")), + (hf32!("-0x1p23"), hf32!("-0x1p23")), + ]); } #[test] - #[cfg(f128_enabled)] - fn zeroes_f128() { - assert_biteq!(generic::round(0.0_f128), 0.0_f128); - assert_biteq!(generic::round(-0.0_f128), -0.0_f128); + fn check_f64() { + check::(&cases!(f64)); + check::(&[ + (hf64!("0x1p52"), hf64!("0x1p52")), + (hf64!("-0x1p52"), hf64!("-0x1p52")), + ]); } #[test] #[cfg(f128_enabled)] - fn sanity_check_f128() { - assert_eq!(generic::round(-1.0_f128), -1.0); - assert_eq!(generic::round(2.8_f128), 3.0); - assert_eq!(generic::round(-0.5_f128), -1.0); - assert_eq!(generic::round(0.5_f128), 1.0); - assert_eq!(generic::round(-1.5_f128), -2.0); - assert_eq!(generic::round(1.5_f128), 2.0); + fn check_f128() { + check::(&cases!(f128)); + check::(&[ + (hf128!("0x1p112"), hf128!("0x1p112")), + (hf128!("-0x1p112"), hf128!("-0x1p112")), + ]); } } diff --git a/library/compiler-builtins/libm/src/math/trunc.rs b/library/compiler-builtins/libm/src/math/trunc.rs index a328c2f8f7d08..8dff82e938ece 100644 --- a/library/compiler-builtins/libm/src/math/trunc.rs +++ b/library/compiler-builtins/libm/src/math/trunc.rs @@ -82,7 +82,7 @@ mod tests { fn check(cases: &[(F, F, Status)]) { for &(x, exp_res, exp_stat) in cases { let FpResult { val, status } = generic::trunc_status(x); - assert_biteq!(val, exp_res, "{x:?} {}", Hex(x)); + assert_biteq!(val, exp_res, "trunc({x:?}) ({})", Hex(x)); assert_eq!( status, exp_stat, @@ -123,7 +123,7 @@ mod tests { #[test] #[cfg(f128_enabled)] - fn spec_tests_f128() { + fn check_f128() { check::(&cases!(f128)); check::(&[ (hf128!("0x1p112"), hf128!("0x1p112"), Status::OK), From cc4523f52648dbfac4c71e07d213f1907161e752 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Mon, 30 Mar 2026 04:48:15 -0500 Subject: [PATCH 056/183] test: Increase the ULP allowed against musl for `tanhf` thread 'musl_random_tanhf' (76230) panicked at libm-test/tests/compare_built_musl.rs:26:50: called `Result::unwrap()` on an `Err` value: input: (0.24503659,) as hex: (0x1.f5d5bep-3,) as bits: (0x1.f5d5bep-3,) expected: 0.24024732 0x1.ec06cap-3 0x1.ec06cap-3 actual: 0.24024737 0x1.ec06d0p-3 0x1.ec06d0p-3 Caused by: ulp 3 > 2 thread 'musl_quickspace_tanhf' (38650234) panicked at libm-test/tests/compare_built_musl.rs:26:50: called `Result::unwrap()` on an `Err` value: input: (0.19125812,) as hex: (0x1.87b256p-3,) as bits: (0x1.87b256p-3,) expected: 0.18895967 0x1.82fd4ap-3 0x1.82fd4ap-3 actual: 0.18895972 0x1.82fd50p-3 0x1.82fd50p-3 Caused by: ulp 3 > 2 --- .../compiler-builtins/libm-test/src/generate/case_list.rs | 6 +++++- library/compiler-builtins/libm-test/src/precision.rs | 1 + 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/library/compiler-builtins/libm-test/src/generate/case_list.rs b/library/compiler-builtins/libm-test/src/generate/case_list.rs index ea4b8028805a5..c3dbca1c355da 100644 --- a/library/compiler-builtins/libm-test/src/generate/case_list.rs +++ b/library/compiler-builtins/libm-test/src/generate/case_list.rs @@ -1501,7 +1501,11 @@ fn tanh_cases() -> Vec> { } fn tanhf_cases() -> Vec> { - cases![] + cases![ + // Inaccuracy in musl + ((0.24503659,), 0.24024734), + ((0.19125812,), 0.18895969), + ] } fn tgamma_cases() -> Vec> { diff --git a/library/compiler-builtins/libm-test/src/precision.rs b/library/compiler-builtins/libm-test/src/precision.rs index dbee911596c27..951aba6763884 100644 --- a/library/compiler-builtins/libm-test/src/precision.rs +++ b/library/compiler-builtins/libm-test/src/precision.rs @@ -171,6 +171,7 @@ pub fn default_ulp(ctx: &CheckCtx) -> Option { Id::Exp2f => ulp = 1, Id::Expf => ulp = 1, Id::Tanh => ulp = 4, + Id::Tanhf => ulp = 4, _ => (), } From 419cad6d7e2670d26abfcd6ca001378a853807e8 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Mon, 30 Mar 2026 04:35:29 -0500 Subject: [PATCH 057/183] ci: Also use nextest to run compiler-builtins tests Currently nextest is always installed but only used for libm. Enable it for compiler-builtins too to help speed up CI. --- library/compiler-builtins/ci/run.sh | 51 ++++++++++++++++------------- 1 file changed, 28 insertions(+), 23 deletions(-) diff --git a/library/compiler-builtins/ci/run.sh b/library/compiler-builtins/ci/run.sh index 766dbb91c598e..06e3460380fe4 100755 --- a/library/compiler-builtins/ci/run.sh +++ b/library/compiler-builtins/ci/run.sh @@ -20,11 +20,37 @@ if [ "${USING_CONTAINER_RUSTC:-}" = 1 ]; then rustup target add "$target" fi +# If nextest is available, use that +command -v cargo-nextest && nextest=1 || nextest=0 +if [ "$nextest" = "1" ]; then + test_runner=(cargo nextest run --max-fail=20) + profile_flag="--cargo-profile" + + # Workaround for https://github.com/nextest-rs/nextest/issues/2066 + if [ -n "${CARGO_TARGET_DIR:-}" ]; then + cfg_file="/tmp/nextest-config.toml" + echo "[store]" >> "$cfg_file" + echo "dir = \"$CARGO_TARGET_DIR/nextest\"" >> "$cfg_file" + test_runner+=(--config-file "$cfg_file") + fi + + # Not all configurations have tests to run on wasm + [[ "$target" = *"wasm"* ]] && test_runner+=(--no-tests=warn) +else + test_runner=(cargo test --no-fail-fast) + profile_flag="--profile" +fi + # Test our implementation if [ "${BUILD_ONLY:-}" = "1" ]; then echo "no tests to run for build-only targets" else - test_builtins=(cargo test --package builtins-test --no-fail-fast --target "$target") + test_builtins=( + "${test_runner[@]}" + --package builtins-test + --target "$target" + ) + "${test_builtins[@]}" "${test_builtins[@]}" --release "${test_builtins[@]}" --features c @@ -157,28 +183,7 @@ if [ "${BUILD_ONLY:-}" = "1" ]; then else # symcheck tests need specific env setup, and is already tested above mflags+=(--workspace --exclude symbol-check --target "$target") - cmd=(cargo test "${mflags[@]}") - profile_flag="--profile" - - # If nextest is available, use that - command -v cargo-nextest && nextest=1 || nextest=0 - if [ "$nextest" = "1" ]; then - cmd=(cargo nextest run --max-fail=10) - - # Workaround for https://github.com/nextest-rs/nextest/issues/2066 - if [ -n "${CARGO_TARGET_DIR:-}" ]; then - cfg_file="/tmp/nextest-config.toml" - echo "[store]" >> "$cfg_file" - echo "dir = \"$CARGO_TARGET_DIR/nextest\"" >> "$cfg_file" - cmd+=(--config-file "$cfg_file") - fi - - # Not all configurations have tests to run on wasm - [[ "$target" = *"wasm"* ]] && cmd+=(--no-tests=warn) - - cmd+=("${mflags[@]}") - profile_flag="--cargo-profile" - fi + cmd=("${test_runner[@]}" "${mflags[@]}") # Test once without intrinsics "${cmd[@]}" From 1560c85df498758fe9db57c8395aafec397c36b1 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Sun, 29 Mar 2026 20:59:12 -0500 Subject: [PATCH 058/183] config: Replace `cfg(x86_no_sse)` with `cfg(x86_no_sse2)` We use this option for both `f32`- and `f64`-related configuration, but the original SSE only had support for single-precision operations. Update this config to check for the SSE2 feature instead, which includes double-precision support. In practice this config is mostly used to differentiate between the i586 target (no SSE required) and the i686 target (SSE2 required) so for that purpose, the existing behavior is fine. Building on an i586 baseline with SSE enabled (but not sse2) also isn't really something we worry about, so this change is mostly only for improving code readability. --- library/compiler-builtins/builtins-test/src/bench.rs | 2 +- .../compiler-builtins/builtins-test/tests/addsub.rs | 4 ++-- .../compiler-builtins/builtins-test/tests/div_rem.rs | 2 +- .../compiler-builtins/builtins-test/tests/float_pow.rs | 4 ++-- library/compiler-builtins/builtins-test/tests/mul.rs | 4 ++-- .../compiler-builtins/compiler-builtins/configure.rs | 6 +++--- library/compiler-builtins/libm-test/benches/random.rs | 2 +- library/compiler-builtins/libm-test/src/precision.rs | 10 +++++----- library/compiler-builtins/libm/configure.rs | 6 +++--- library/compiler-builtins/libm/src/math/arch/mod.rs | 2 +- library/compiler-builtins/libm/src/math/atan2.rs | 2 +- library/compiler-builtins/libm/src/math/cbrt.rs | 2 +- library/compiler-builtins/libm/src/math/exp.rs | 2 +- library/compiler-builtins/libm/src/math/exp10.rs | 2 +- library/compiler-builtins/libm/src/math/exp10f.rs | 2 +- library/compiler-builtins/libm/src/math/exp2.rs | 2 +- library/compiler-builtins/libm/src/math/exp2f.rs | 2 +- library/compiler-builtins/libm/src/math/expf.rs | 2 +- .../compiler-builtins/libm/src/math/generic/rint.rs | 2 +- library/compiler-builtins/libm/src/math/rem_pio2.rs | 2 +- .../compiler-builtins/libm/src/math/rem_pio2_large.rs | 2 +- library/compiler-builtins/libm/src/math/sin.rs | 2 +- .../libm/src/math/support/float_traits.rs | 4 ++-- .../libm/src/math/support/hex_float.rs | 2 +- 24 files changed, 36 insertions(+), 36 deletions(-) diff --git a/library/compiler-builtins/builtins-test/src/bench.rs b/library/compiler-builtins/builtins-test/src/bench.rs index aafcac4fa7913..dd03579285cbc 100644 --- a/library/compiler-builtins/builtins-test/src/bench.rs +++ b/library/compiler-builtins/builtins-test/src/bench.rs @@ -43,7 +43,7 @@ pub fn skip_sys_checks(test_name: &str) -> bool { return true; } - if cfg!(x86_no_sse) && X86_NO_SSE_SKIPPED.contains(&test_name) { + if cfg!(x86_no_sse2) && X86_NO_SSE_SKIPPED.contains(&test_name) { return true; } diff --git a/library/compiler-builtins/builtins-test/tests/addsub.rs b/library/compiler-builtins/builtins-test/tests/addsub.rs index e19e5400e86a6..de1235bce54fc 100644 --- a/library/compiler-builtins/builtins-test/tests/addsub.rs +++ b/library/compiler-builtins/builtins-test/tests/addsub.rs @@ -113,7 +113,7 @@ macro_rules! float_sum { } } -#[cfg(not(x86_no_sse))] +#[cfg(not(x86_no_sse2))] mod float_addsub { use super::*; @@ -128,7 +128,7 @@ mod float_addsub { } #[cfg(f128_enabled)] - #[cfg(not(x86_no_sse))] + #[cfg(not(x86_no_sse2))] #[cfg(not(any(target_arch = "powerpc", target_arch = "powerpc64")))] float_sum! { f128, __addtf3, __subtf3, Quad, not(feature = "no-sys-f128"); diff --git a/library/compiler-builtins/builtins-test/tests/div_rem.rs b/library/compiler-builtins/builtins-test/tests/div_rem.rs index 81d7470ba8736..fccd421828cab 100644 --- a/library/compiler-builtins/builtins-test/tests/div_rem.rs +++ b/library/compiler-builtins/builtins-test/tests/div_rem.rs @@ -139,7 +139,7 @@ macro_rules! float { }; } -#[cfg(not(x86_no_sse))] +#[cfg(not(x86_no_sse2))] mod float_div { use super::*; diff --git a/library/compiler-builtins/builtins-test/tests/float_pow.rs b/library/compiler-builtins/builtins-test/tests/float_pow.rs index bce073a2342b7..750869de3e5a9 100644 --- a/library/compiler-builtins/builtins-test/tests/float_pow.rs +++ b/library/compiler-builtins/builtins-test/tests/float_pow.rs @@ -1,7 +1,7 @@ #![allow(unused_macros, unused_features)] #![cfg_attr(f128_enabled, feature(f128))] -#[cfg_attr(x86_no_sse, allow(unused))] +#[cfg_attr(x86_no_sse2, allow(unused))] use builtins_test::*; // This is approximate because of issues related to @@ -53,7 +53,7 @@ macro_rules! pow { }; } -#[cfg(not(x86_no_sse))] // FIXME(i586): failure for powidf2 +#[cfg(not(x86_no_sse2))] // FIXME(i586): failure for powidf2 pow! { f32, 1e-4, __powisf2, all(); f64, 1e-12, __powidf2, all(); diff --git a/library/compiler-builtins/builtins-test/tests/mul.rs b/library/compiler-builtins/builtins-test/tests/mul.rs index 3af61fe0d2916..7c3bffe4b159a 100644 --- a/library/compiler-builtins/builtins-test/tests/mul.rs +++ b/library/compiler-builtins/builtins-test/tests/mul.rs @@ -115,7 +115,7 @@ macro_rules! float_mul { }; } -#[cfg(not(x86_no_sse))] +#[cfg(not(x86_no_sse2))] mod float_mul { use super::*; @@ -133,7 +133,7 @@ mod float_mul { } #[cfg(f128_enabled)] -#[cfg(not(x86_no_sse))] +#[cfg(not(x86_no_sse2))] #[cfg(not(any(target_arch = "powerpc", target_arch = "powerpc64")))] mod float_mul_f128 { use super::*; diff --git a/library/compiler-builtins/compiler-builtins/configure.rs b/library/compiler-builtins/compiler-builtins/configure.rs index f16da6b58f812..874397aa48486 100644 --- a/library/compiler-builtins/compiler-builtins/configure.rs +++ b/library/compiler-builtins/compiler-builtins/configure.rs @@ -82,10 +82,10 @@ pub fn configure_aliases(target: &Target) { } // Config shorthands - println!("cargo:rustc-check-cfg=cfg(x86_no_sse)"); - if target.arch == "x86" && !target.features.iter().any(|f| f == "sse") { + println!("cargo:rustc-check-cfg=cfg(x86_no_sse2)"); + if target.arch == "x86" && !target.features.iter().any(|f| f == "sse2") { // Shorthand to detect i586 targets - println!("cargo:rustc-cfg=x86_no_sse"); + println!("cargo:rustc-cfg=x86_no_sse2"); } /* Not all backends support `f16` and `f128` to the same level on all architectures, so we diff --git a/library/compiler-builtins/libm-test/benches/random.rs b/library/compiler-builtins/libm-test/benches/random.rs index 8810d4d659dfa..ae4c2f51bdec5 100644 --- a/library/compiler-builtins/libm-test/benches/random.rs +++ b/library/compiler-builtins/libm-test/benches/random.rs @@ -69,7 +69,7 @@ where use anyhow::Context; use libm_test::CheckOutput; - if cfg!(x86_no_sse) && musl_extra.skip_on_i586 { + if cfg!(x86_no_sse2) && musl_extra.skip_on_i586 { break; } diff --git a/library/compiler-builtins/libm-test/src/precision.rs b/library/compiler-builtins/libm-test/src/precision.rs index 951aba6763884..64d8cc7f8d277 100644 --- a/library/compiler-builtins/libm-test/src/precision.rs +++ b/library/compiler-builtins/libm-test/src/precision.rs @@ -115,7 +115,7 @@ pub fn default_ulp(ctx: &CheckCtx) -> Option { let mut orig_ulp = ulp; // These have a separate implementation on i586 which is more accurate. - if cfg!(x86_no_sse) { + if cfg!(x86_no_sse2) { match ctx.fn_ident { Id::Exp => ulp = 1, Id::Exp2 => ulp = 1, @@ -166,8 +166,8 @@ pub fn default_ulp(ctx: &CheckCtx) -> Option { Id::Cbrt => ulp = 2, Id::Cosh => ulp = 2, Id::Coshf => ulp = 2, - Id::Exp10 if cfg!(x86_no_sse) => ulp = 4, - Id::Exp10f if cfg!(x86_no_sse) => ulp = 4, + Id::Exp10 if cfg!(x86_no_sse2) => ulp = 4, + Id::Exp10f if cfg!(x86_no_sse2) => ulp = 4, Id::Exp2f => ulp = 1, Id::Expf => ulp = 1, Id::Tanh => ulp = 4, @@ -294,7 +294,7 @@ impl MaybeOverride<(f32,)> for SpecialCase { impl MaybeOverride<(f64,)> for SpecialCase { fn check_float(input: (f64,), actual: F, expected: F, ctx: &CheckCtx) -> CheckAction { - if cfg!(x86_no_sse) + if cfg!(x86_no_sse2) && (ctx.base_name == BaseName::Rint || ctx.base_name == BaseName::Roundeven) && (expected - actual).abs() <= F::ONE && (expected - actual).abs() > F::ZERO @@ -533,7 +533,7 @@ fn int_float_common( // Our bessel functions blow up with large N values if ctx.base_name == BaseName::Jn || ctx.base_name == BaseName::Yn { - if cfg!(x86_no_sse) { + if cfg!(x86_no_sse2) { // Precision is especially bad on i586, not worth checking. return XFAIL_NOCHECK; } diff --git a/library/compiler-builtins/libm/configure.rs b/library/compiler-builtins/libm/configure.rs index ee65a3a8d6243..eeace880b7e87 100644 --- a/library/compiler-builtins/libm/configure.rs +++ b/library/compiler-builtins/libm/configure.rs @@ -111,10 +111,10 @@ fn emit_optimization_cfg(cfg: &Config) { /// Provide an alias for common longer config combinations. fn emit_cfg_shorthands(cfg: &Config) { - println!("cargo:rustc-check-cfg=cfg(x86_no_sse)"); - if cfg.target_arch == "x86" && !cfg.target_features.iter().any(|f| f == "sse") { + println!("cargo:rustc-check-cfg=cfg(x86_no_sse2)"); + if cfg.target_arch == "x86" && !cfg.target_features.iter().any(|f| f == "sse2") { // Shorthand to detect i586 targets - println!("cargo:rustc-cfg=x86_no_sse"); + println!("cargo:rustc-cfg=x86_no_sse2"); } } diff --git a/library/compiler-builtins/libm/src/math/arch/mod.rs b/library/compiler-builtins/libm/src/math/arch/mod.rs index ba859c679d0db..6b1e24223216d 100644 --- a/library/compiler-builtins/libm/src/math/arch/mod.rs +++ b/library/compiler-builtins/libm/src/math/arch/mod.rs @@ -49,7 +49,7 @@ cfg_if! { } } cfg_if! { - if #[cfg(x86_no_sse)] { + if #[cfg(x86_no_sse2)] { pub use i586::{x87_exp10f, x87_exp10, x87_expf, x87_exp, x87_exp2f, x87_exp2}; } } diff --git a/library/compiler-builtins/libm/src/math/atan2.rs b/library/compiler-builtins/libm/src/math/atan2.rs index 51456e409b8cc..19be7584bbf07 100644 --- a/library/compiler-builtins/libm/src/math/atan2.rs +++ b/library/compiler-builtins/libm/src/math/atan2.rs @@ -119,7 +119,7 @@ mod tests { use super::*; #[test] - #[cfg_attr(x86_no_sse, ignore = "FIXME(i586): possible incorrect rounding")] + #[cfg_attr(x86_no_sse2, ignore = "FIXME(i586): possible incorrect rounding")] fn sanity_check() { assert_eq!(atan2(0.0, 1.0), 0.0); assert_eq!(atan2(0.0, -1.0), PI); diff --git a/library/compiler-builtins/libm/src/math/cbrt.rs b/library/compiler-builtins/libm/src/math/cbrt.rs index e905e15f13fbe..b6d24c807eb00 100644 --- a/library/compiler-builtins/libm/src/math/cbrt.rs +++ b/library/compiler-builtins/libm/src/math/cbrt.rs @@ -208,7 +208,7 @@ mod tests { #[test] fn spot_checks() { - if !cfg!(x86_no_sse) { + if !cfg!(x86_no_sse2) { // Exposes a rounding mode problem. Ignored on i586 because of inaccurate FMA. assert_biteq!( cbrt(f64::from_bits(0xf7f792b28f600000)), diff --git a/library/compiler-builtins/libm/src/math/exp.rs b/library/compiler-builtins/libm/src/math/exp.rs index cb939ad5d8bf2..05203985bf313 100644 --- a/library/compiler-builtins/libm/src/math/exp.rs +++ b/library/compiler-builtins/libm/src/math/exp.rs @@ -85,7 +85,7 @@ const P5: f64 = 4.13813679705723846039e-08; /* 0x3E663769, 0x72BEA4D0 */ pub fn exp(mut x: f64) -> f64 { select_implementation! { name: x87_exp, - use_arch_required: x86_no_sse, + use_arch_required: x86_no_sse2, args: x, } diff --git a/library/compiler-builtins/libm/src/math/exp10.rs b/library/compiler-builtins/libm/src/math/exp10.rs index e0af1945b922a..452b29a2c3d14 100644 --- a/library/compiler-builtins/libm/src/math/exp10.rs +++ b/library/compiler-builtins/libm/src/math/exp10.rs @@ -11,7 +11,7 @@ const P10: &[f64] = &[ pub fn exp10(x: f64) -> f64 { select_implementation! { name: x87_exp10, - use_arch_required: x86_no_sse, + use_arch_required: x86_no_sse2, args: x, } diff --git a/library/compiler-builtins/libm/src/math/exp10f.rs b/library/compiler-builtins/libm/src/math/exp10f.rs index f0a311c2d1915..4b9e949fbbe97 100644 --- a/library/compiler-builtins/libm/src/math/exp10f.rs +++ b/library/compiler-builtins/libm/src/math/exp10f.rs @@ -11,7 +11,7 @@ const P10: &[f32] = &[ pub fn exp10f(x: f32) -> f32 { select_implementation! { name: x87_exp10f, - use_arch_required: x86_no_sse, + use_arch_required: x86_no_sse2, args: x, } diff --git a/library/compiler-builtins/libm/src/math/exp2.rs b/library/compiler-builtins/libm/src/math/exp2.rs index d4c9e96652000..cc2aa434c4e9d 100644 --- a/library/compiler-builtins/libm/src/math/exp2.rs +++ b/library/compiler-builtins/libm/src/math/exp2.rs @@ -326,7 +326,7 @@ static TBL: [u64; TBLSIZE * 2] = [ pub fn exp2(mut x: f64) -> f64 { select_implementation! { name: x87_exp2, - use_arch_required: x86_no_sse, + use_arch_required: x86_no_sse2, args: x, } diff --git a/library/compiler-builtins/libm/src/math/exp2f.rs b/library/compiler-builtins/libm/src/math/exp2f.rs index ceff6822c5969..44872d74b0ca8 100644 --- a/library/compiler-builtins/libm/src/math/exp2f.rs +++ b/library/compiler-builtins/libm/src/math/exp2f.rs @@ -77,7 +77,7 @@ static EXP2FT: [u64; TBLSIZE] = [ pub fn exp2f(mut x: f32) -> f32 { select_implementation! { name: x87_exp2f, - use_arch_required: x86_no_sse, + use_arch_required: x86_no_sse2, args: x, } diff --git a/library/compiler-builtins/libm/src/math/expf.rs b/library/compiler-builtins/libm/src/math/expf.rs index 5541ab79a9c14..d1185ff2c4621 100644 --- a/library/compiler-builtins/libm/src/math/expf.rs +++ b/library/compiler-builtins/libm/src/math/expf.rs @@ -34,7 +34,7 @@ const P2: f32 = -2.7667332906e-3; /* -0xb55215.0p-32 */ pub fn expf(mut x: f32) -> f32 { select_implementation! { name: x87_expf, - use_arch_required: x86_no_sse, + use_arch_required: x86_no_sse2, args: x, } diff --git a/library/compiler-builtins/libm/src/math/generic/rint.rs b/library/compiler-builtins/libm/src/math/generic/rint.rs index fb0d68249a3e5..aa3d94e9a30d8 100644 --- a/library/compiler-builtins/libm/src/math/generic/rint.rs +++ b/library/compiler-builtins/libm/src/math/generic/rint.rs @@ -14,7 +14,7 @@ pub fn rint_status(x: F) -> FpResult { // On i386 `force_eval!` must be used to force rounding via storage to memory. Otherwise, // the excess precission from x87 would cause an incorrect final result. let force = |x| { - if cfg!(x86_no_sse) && (F::BITS == 32 || F::BITS == 64) { + if cfg!(x86_no_sse2) && (F::BITS == 32 || F::BITS == 64) { force_eval!(x) } else { x diff --git a/library/compiler-builtins/libm/src/math/rem_pio2.rs b/library/compiler-builtins/libm/src/math/rem_pio2.rs index 61b1030275a22..5fe26f433c9e0 100644 --- a/library/compiler-builtins/libm/src/math/rem_pio2.rs +++ b/library/compiler-builtins/libm/src/math/rem_pio2.rs @@ -195,7 +195,7 @@ mod tests { #[test] // FIXME(correctness): inaccurate results on i586 - #[cfg_attr(x86_no_sse, ignore)] + #[cfg_attr(x86_no_sse2, ignore)] fn test_near_pi() { let arg = 3.141592025756836; let arg = force_eval!(arg); diff --git a/library/compiler-builtins/libm/src/math/rem_pio2_large.rs b/library/compiler-builtins/libm/src/math/rem_pio2_large.rs index 841a51b84c278..8212c1a0a9f42 100644 --- a/library/compiler-builtins/libm/src/math/rem_pio2_large.rs +++ b/library/compiler-builtins/libm/src/math/rem_pio2_large.rs @@ -228,7 +228,7 @@ pub(crate) fn rem_pio2_large(x: &[f64], y: &mut [f64], e0: i32, prec: usize) -> // FIXME(rust-lang/rust#144518): Inline assembly would cause `no_panic` to fail // on the callers of this function. As a workaround, avoid inlining `floor` here // when implemented with assembly. - #[cfg_attr(x86_no_sse, inline(never))] + #[cfg_attr(x86_no_sse2, inline(never))] extern "C" fn floor(x: f64) -> f64 { super::floor(x) } diff --git a/library/compiler-builtins/libm/src/math/sin.rs b/library/compiler-builtins/libm/src/math/sin.rs index 5378a7bc3874a..2f54074c25ef0 100644 --- a/library/compiler-builtins/libm/src/math/sin.rs +++ b/library/compiler-builtins/libm/src/math/sin.rs @@ -86,7 +86,7 @@ mod tests { use super::*; #[test] - #[cfg_attr(x86_no_sse, ignore = "FIXME(i586): possible incorrect rounding")] + #[cfg_attr(x86_no_sse2, ignore = "FIXME(i586): possible incorrect rounding")] fn test_near_pi() { let x = f64::from_bits(0x400921fb000FD5DD); // 3.141592026217707 let sx = f64::from_bits(0x3ea50d15ced1a4a2); // 6.273720864039205e-7 diff --git a/library/compiler-builtins/libm/src/math/support/float_traits.rs b/library/compiler-builtins/libm/src/math/support/float_traits.rs index 55ffadea0f7f7..208619e358fc3 100644 --- a/library/compiler-builtins/libm/src/math/support/float_traits.rs +++ b/library/compiler-builtins/libm/src/math/support/float_traits.rs @@ -569,7 +569,7 @@ mod tests { } assert!(f32::NAN.is_qnan()); // FIXME(rust-lang/rust#115567): x87 use in `is_snan` quiets the sNaN - if !cfg!(x86_no_sse) { + if !cfg!(x86_no_sse2) { assert!(f32::SNAN.is_snan()); } @@ -614,7 +614,7 @@ mod tests { } assert!(f64::NAN.is_qnan()); // FIXME(rust-lang/rust#115567): x87 use in `is_snan` quiets the sNaN - if !cfg!(x86_no_sse) { + if !cfg!(x86_no_sse2) { assert!(f64::SNAN.is_snan()); } diff --git a/library/compiler-builtins/libm/src/math/support/hex_float.rs b/library/compiler-builtins/libm/src/math/support/hex_float.rs index e38ef50ffdeb8..28aab7ef27a1c 100644 --- a/library/compiler-builtins/libm/src/math/support/hex_float.rs +++ b/library/compiler-builtins/libm/src/math/support/hex_float.rs @@ -1162,7 +1162,7 @@ mod print_tests { assert_eq!(Hex(f64::NAN).to_string(), "qNaN"); assert_eq!(Hex(f32::NEG_NAN).to_string(), "-qNaN"); assert_eq!(Hex(f64::NEG_NAN).to_string(), "-qNaN"); - if !cfg!(x86_no_sse) { + if !cfg!(x86_no_sse2) { // FIXME(rust-lang/rust#115567): calls quiet the sNaN assert_eq!(Hex(f32::SNAN).to_string(), "sNaN"); assert_eq!(Hex(f64::SNAN).to_string(), "sNaN"); From b10da67cfcc969311b1592cf3919a4b8ebe4b87a Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Sun, 29 Mar 2026 20:55:29 -0500 Subject: [PATCH 059/183] libm: Use the shorthand `cfg(x86_no_sse2)` in more places --- .../libm/src/math/arch/mod.rs | 18 +++++++++++------- .../compiler-builtins/libm/src/math/ceil.rs | 2 +- .../compiler-builtins/libm/src/math/floor.rs | 2 +- library/compiler-builtins/libm/src/math/fma.rs | 2 +- library/compiler-builtins/libm/src/math/j1f.rs | 3 +-- library/compiler-builtins/libm/src/math/pow.rs | 4 ++-- .../libm/src/math/rem_pio2.rs | 2 +- .../libm/src/math/rem_pio2f.rs | 2 +- 8 files changed, 19 insertions(+), 16 deletions(-) diff --git a/library/compiler-builtins/libm/src/math/arch/mod.rs b/library/compiler-builtins/libm/src/math/arch/mod.rs index 6b1e24223216d..6b86cce3497d5 100644 --- a/library/compiler-builtins/libm/src/math/arch/mod.rs +++ b/library/compiler-builtins/libm/src/math/arch/mod.rs @@ -42,14 +42,18 @@ cfg_if! { // There are certain architecture-specific implementations that are needed for correctness // even with `force-soft-float`. These are configured here. -cfg_if! { - if #[cfg(all(target_arch = "x86", not(target_feature = "sse2")))] { - mod i586; - pub use i586::{ceil, floor}; - } -} cfg_if! { if #[cfg(x86_no_sse2)] { - pub use i586::{x87_exp10f, x87_exp10, x87_expf, x87_exp, x87_exp2f, x87_exp2}; + mod i586; + pub use i586::{ + ceil, + floor, + x87_exp, + x87_exp10, + x87_exp10f, + x87_exp2, + x87_exp2f, + x87_expf, + }; } } diff --git a/library/compiler-builtins/libm/src/math/ceil.rs b/library/compiler-builtins/libm/src/math/ceil.rs index 4dc2e175ac459..816ae9d8bd906 100644 --- a/library/compiler-builtins/libm/src/math/ceil.rs +++ b/library/compiler-builtins/libm/src/math/ceil.rs @@ -31,7 +31,7 @@ pub fn ceil(x: f64) -> f64 { select_implementation! { name: ceil, use_arch: all(target_arch = "wasm32", intrinsics_enabled), - use_arch_required: all(target_arch = "x86", not(target_feature = "sse2")), + use_arch_required: x86_no_sse2, args: x, } diff --git a/library/compiler-builtins/libm/src/math/floor.rs b/library/compiler-builtins/libm/src/math/floor.rs index d6bd2113b047b..4d459084f7045 100644 --- a/library/compiler-builtins/libm/src/math/floor.rs +++ b/library/compiler-builtins/libm/src/math/floor.rs @@ -17,7 +17,7 @@ pub fn floor(x: f64) -> f64 { select_implementation! { name: floor, use_arch: all(target_arch = "wasm32", intrinsics_enabled), - use_arch_required: all(target_arch = "x86", not(target_feature = "sse2")), + use_arch_required: x86_no_sse2, args: x, } diff --git a/library/compiler-builtins/libm/src/math/fma.rs b/library/compiler-builtins/libm/src/math/fma.rs index 70e6de768fab0..7f8120650a8d9 100644 --- a/library/compiler-builtins/libm/src/math/fma.rs +++ b/library/compiler-builtins/libm/src/math/fma.rs @@ -148,7 +148,7 @@ mod tests { let result = fma(-0.992, -0.992, -0.992); //force rounding to storage format on x87 to prevent superious errors. - #[cfg(all(target_arch = "x86", not(target_feature = "sse2")))] + #[cfg(x86_no_sse2)] let result = force_eval!(result); assert_eq!(result, -0.007936000000000007,); } diff --git a/library/compiler-builtins/libm/src/math/j1f.rs b/library/compiler-builtins/libm/src/math/j1f.rs index cd829c1aa1213..d545a8635b127 100644 --- a/library/compiler-builtins/libm/src/math/j1f.rs +++ b/library/compiler-builtins/libm/src/math/j1f.rs @@ -374,8 +374,7 @@ mod tests { fn test_y1f_2002() { //allow slightly different result on x87 let res = y1f(2.0000002_f32); - if cfg!(all(target_arch = "x86", not(target_feature = "sse2"))) && (res == -0.10703231_f32) - { + if cfg!(x86_no_sse2) && (res == -0.10703231_f32) { return; } assert_eq!(res, -0.10703229_f32); diff --git a/library/compiler-builtins/libm/src/math/pow.rs b/library/compiler-builtins/libm/src/math/pow.rs index 914d68cfce1a2..87eaab3c7c727 100644 --- a/library/compiler-builtins/libm/src/math/pow.rs +++ b/library/compiler-builtins/libm/src/math/pow.rs @@ -472,9 +472,9 @@ mod tests { let exp = expected(*val); let res = computed(*val); - #[cfg(all(target_arch = "x86", not(target_feature = "sse2")))] + #[cfg(x86_no_sse2)] let exp = force_eval!(exp); - #[cfg(all(target_arch = "x86", not(target_feature = "sse2")))] + #[cfg(x86_no_sse2)] let res = force_eval!(res); assert!( if exp.is_nan() { diff --git a/library/compiler-builtins/libm/src/math/rem_pio2.rs b/library/compiler-builtins/libm/src/math/rem_pio2.rs index 5fe26f433c9e0..d2be3957358ae 100644 --- a/library/compiler-builtins/libm/src/math/rem_pio2.rs +++ b/library/compiler-builtins/libm/src/math/rem_pio2.rs @@ -53,7 +53,7 @@ pub(crate) fn rem_pio2(x: f64) -> (i32, f64, f64) { let tmp = x * INV_PIO2 + TO_INT; // force rounding of tmp to it's storage format on x87 to avoid // excess precision issues. - #[cfg(all(target_arch = "x86", not(target_feature = "sse2")))] + #[cfg(x86_no_sse2)] let tmp = force_eval!(tmp); let f_n = tmp - TO_INT; let n = f_n as i32; diff --git a/library/compiler-builtins/libm/src/math/rem_pio2f.rs b/library/compiler-builtins/libm/src/math/rem_pio2f.rs index 481f7ee830bbb..bbf8042752137 100644 --- a/library/compiler-builtins/libm/src/math/rem_pio2f.rs +++ b/library/compiler-builtins/libm/src/math/rem_pio2f.rs @@ -44,7 +44,7 @@ pub(crate) fn rem_pio2f(x: f32) -> (i32, f64) { let tmp = x64 * INV_PIO2 + TOINT; // force rounding of tmp to it's storage format on x87 to avoid // excess precision issues. - #[cfg(all(target_arch = "x86", not(target_feature = "sse2")))] + #[cfg(x86_no_sse2)] let tmp = force_eval!(tmp); let f_n = tmp - TOINT; return (f_n as i32, x64 - f_n * PIO2_1 - f_n * PIO2_1T); From 7803d01f1beb96cf4233a214da13f58c54961f37 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Mon, 30 Mar 2026 15:10:54 -0400 Subject: [PATCH 060/183] test: Benchmark i256 right shifts Additionally, update the formatting of the macro invocations to use the new syntax. --- .../libm-test/benches/icount.rs | 48 +++++++++++++------ 1 file changed, 33 insertions(+), 15 deletions(-) diff --git a/library/compiler-builtins/libm-test/benches/icount.rs b/library/compiler-builtins/libm-test/benches/icount.rs index 2fd46244deeef..28a69e747fd3a 100644 --- a/library/compiler-builtins/libm-test/benches/icount.rs +++ b/library/compiler-builtins/libm-test/benches/icount.rs @@ -5,7 +5,7 @@ use std::hint::black_box; use gungraun::{library_benchmark, library_benchmark_group, main}; -use libm::support::{HInt, Hex, hf16, hf32, hf64, hf128, u256}; +use libm::support::{HInt, Hex, hf16, hf32, hf64, hf128, i256, u256}; use libm_test::generate::spaced; use libm_test::{CheckBasis, CheckCtx, GeneratorKind, MathOp, OpRustArgs, TupleCall, op}; @@ -103,6 +103,13 @@ fn setup_u256_shift() -> Vec<(u256, u32)> { v } +fn setup_i256_shift() -> Vec<(i256, u32)> { + setup_u256_shift() + .into_iter() + .map(|(x, i)| (x.signed(), i)) + .collect() +} + #[library_benchmark] #[bench::linspace(setup_u128_mul())] fn icount_bench_u128_widen_mul(cases: Vec<(u128, u128)>) { @@ -154,15 +161,25 @@ fn icount_bench_u256_shr(cases: Vec<(u256, u32)>) { } } +#[library_benchmark] +#[bench::linspace(setup_i256_shift())] +fn icount_bench_i256_shr(cases: Vec<(i256, u32)>) { + for (x, y) in cases.iter().copied() { + black_box(black_box(x) >> black_box(y)); + } +} + library_benchmark_group!( - name = icount_bench_u128_group; - benchmarks = - icount_bench_u128_widen_mul, - icount_bench_u256_narrowing_div, - icount_bench_u256_add, - icount_bench_u256_sub, - icount_bench_u256_shl, - icount_bench_u256_shr + name = icount_bench_u128_group, + benchmarks = [ + icount_bench_u128_widen_mul, + icount_bench_u256_narrowing_div, + icount_bench_u256_add, + icount_bench_u256_sub, + icount_bench_u256_shl, + icount_bench_u256_shr, + icount_bench_i256_shr, + ] ); #[library_benchmark] @@ -194,12 +211,13 @@ fn icount_bench_hf128(s: &str) -> f128 { } library_benchmark_group!( - name = icount_bench_hf_parse_group; - benchmarks = - icount_bench_hf16, - icount_bench_hf32, - icount_bench_hf64, - icount_bench_hf128 + name = icount_bench_hf_parse_group, + benchmarks = [ + icount_bench_hf16, + icount_bench_hf32, + icount_bench_hf64, + icount_bench_hf128, + ] ); #[library_benchmark] From e273f945c80b2260d39e376212b7ac4ff6338302 Mon Sep 17 00:00:00 2001 From: Marco Ieni <11428655+marcoieni@users.noreply.github.com> Date: Mon, 30 Mar 2026 23:32:29 +0200 Subject: [PATCH 061/183] ci: Rename updateTypes to matchUpdateTypes in renovate config See https://github.com/rust-lang/team/pull/2359 --- library/compiler-builtins/.github/renovate.json5 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/.github/renovate.json5 b/library/compiler-builtins/.github/renovate.json5 index 1937b1c6d34a8..6a269ab449861 100644 --- a/library/compiler-builtins/.github/renovate.json5 +++ b/library/compiler-builtins/.github/renovate.json5 @@ -10,7 +10,7 @@ matchCategories: [ "rust" ], - updateTypes: [ + matchUpdateTypes: [ "patch" ], // Disable patch updates for single dependencies because patches From 3d384fae243bb98d07fd089a20862f8f347d6154 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Mon, 30 Mar 2026 15:58:22 -0400 Subject: [PATCH 062/183] test: Also test the non-generic function for rounding ops --- .../compiler-builtins/libm/src/math/ceil.rs | 58 ++++++++++++------- .../compiler-builtins/libm/src/math/floor.rs | 58 ++++++++++++------- .../compiler-builtins/libm/src/math/rint.rs | 58 ++++++++++++------- .../compiler-builtins/libm/src/math/round.rs | 56 +++++++++++------- .../compiler-builtins/libm/src/math/trunc.rs | 58 ++++++++++++------- 5 files changed, 179 insertions(+), 109 deletions(-) diff --git a/library/compiler-builtins/libm/src/math/ceil.rs b/library/compiler-builtins/libm/src/math/ceil.rs index 816ae9d8bd906..c8fb17e7ddca1 100644 --- a/library/compiler-builtins/libm/src/math/ceil.rs +++ b/library/compiler-builtins/libm/src/math/ceil.rs @@ -80,10 +80,10 @@ mod tests { } #[track_caller] - fn check(cases: &[(F, F, Status)]) { + fn check(f: fn(F) -> F, cases: &[(F, F, Status)]) { for &(x, exp_res, exp_stat) in cases { let FpResult { val, status } = generic::ceil_status(x); - assert_biteq!(val, exp_res, "ceil({x:?}) ({})", Hex(x)); + assert_biteq!(val, exp_res, "generic::ceil_status({x:?}) ({})", Hex(x)); assert_eq!( status, exp_stat, @@ -91,44 +91,58 @@ mod tests { Hex(x), Hex(exp_res) ); + let val = f(x); + assert_biteq!(val, exp_res, "ceil({x:?}) ({})", Hex(x)); } } #[test] #[cfg(f16_enabled)] fn check_f16() { - check::(&cases!(f16)); - check::(&[ - (hf16!("0x1p10"), hf16!("0x1p10"), Status::OK), - (hf16!("-0x1p10"), hf16!("-0x1p10"), Status::OK), - ]); + check::(ceilf16, &cases!(f16)); + check::( + ceilf16, + &[ + (hf16!("0x1p10"), hf16!("0x1p10"), Status::OK), + (hf16!("-0x1p10"), hf16!("-0x1p10"), Status::OK), + ], + ); } #[test] fn check_f32() { - check::(&cases!(f32)); - check::(&[ - (hf32!("0x1p23"), hf32!("0x1p23"), Status::OK), - (hf32!("-0x1p23"), hf32!("-0x1p23"), Status::OK), - ]); + check::(ceilf, &cases!(f32)); + check::( + ceilf, + &[ + (hf32!("0x1p23"), hf32!("0x1p23"), Status::OK), + (hf32!("-0x1p23"), hf32!("-0x1p23"), Status::OK), + ], + ); } #[test] fn check_f64() { - check::(&cases!(f64)); - check::(&[ - (hf64!("0x1p52"), hf64!("0x1p52"), Status::OK), - (hf64!("-0x1p52"), hf64!("-0x1p52"), Status::OK), - ]); + check::(ceil, &cases!(f64)); + check::( + ceil, + &[ + (hf64!("0x1p52"), hf64!("0x1p52"), Status::OK), + (hf64!("-0x1p52"), hf64!("-0x1p52"), Status::OK), + ], + ); } #[test] #[cfg(f128_enabled)] fn check_f128() { - check::(&cases!(f128)); - check::(&[ - (hf128!("0x1p112"), hf128!("0x1p112"), Status::OK), - (hf128!("-0x1p112"), hf128!("-0x1p112"), Status::OK), - ]); + check::(ceilf128, &cases!(f128)); + check::( + ceilf128, + &[ + (hf128!("0x1p112"), hf128!("0x1p112"), Status::OK), + (hf128!("-0x1p112"), hf128!("-0x1p112"), Status::OK), + ], + ); } } diff --git a/library/compiler-builtins/libm/src/math/floor.rs b/library/compiler-builtins/libm/src/math/floor.rs index 4d459084f7045..2b1e31c0564b0 100644 --- a/library/compiler-builtins/libm/src/math/floor.rs +++ b/library/compiler-builtins/libm/src/math/floor.rs @@ -80,10 +80,10 @@ mod tests { } #[track_caller] - fn check(cases: &[(F, F, Status)]) { + fn check(f: fn(F) -> F, cases: &[(F, F, Status)]) { for &(x, exp_res, exp_stat) in cases { let FpResult { val, status } = generic::floor_status(x); - assert_biteq!(val, exp_res, "floor({x:?}) ({})", Hex(x)); + assert_biteq!(val, exp_res, "generic::floor_status({x:?}) ({})", Hex(x)); assert_eq!( status, exp_stat, @@ -91,44 +91,58 @@ mod tests { Hex(x), Hex(exp_res) ); + let val = f(x); + assert_biteq!(val, exp_res, "floor({x:?}) ({})", Hex(x)); } } #[test] #[cfg(f16_enabled)] fn check_f16() { - check::(&cases!(f16)); - check::(&[ - (hf16!("0x1p10"), hf16!("0x1p10"), Status::OK), - (hf16!("-0x1p10"), hf16!("-0x1p10"), Status::OK), - ]); + check::(floorf16, &cases!(f16)); + check::( + floorf16, + &[ + (hf16!("0x1p10"), hf16!("0x1p10"), Status::OK), + (hf16!("-0x1p10"), hf16!("-0x1p10"), Status::OK), + ], + ); } #[test] fn check_f32() { - check::(&cases!(f32)); - check::(&[ - (hf32!("0x1p23"), hf32!("0x1p23"), Status::OK), - (hf32!("-0x1p23"), hf32!("-0x1p23"), Status::OK), - ]); + check::(floorf, &cases!(f32)); + check::( + floorf, + &[ + (hf32!("0x1p23"), hf32!("0x1p23"), Status::OK), + (hf32!("-0x1p23"), hf32!("-0x1p23"), Status::OK), + ], + ); } #[test] fn check_f64() { - check::(&cases!(f64)); - check::(&[ - (hf64!("0x1p52"), hf64!("0x1p52"), Status::OK), - (hf64!("-0x1p52"), hf64!("-0x1p52"), Status::OK), - ]); + check::(floor, &cases!(f64)); + check::( + floor, + &[ + (hf64!("0x1p52"), hf64!("0x1p52"), Status::OK), + (hf64!("-0x1p52"), hf64!("-0x1p52"), Status::OK), + ], + ); } #[test] #[cfg(f128_enabled)] fn check_f128() { - check::(&cases!(f128)); - check::(&[ - (hf128!("0x1p112"), hf128!("0x1p112"), Status::OK), - (hf128!("-0x1p112"), hf128!("-0x1p112"), Status::OK), - ]); + check::(floorf128, &cases!(f128)); + check::( + floorf128, + &[ + (hf128!("0x1p112"), hf128!("0x1p112"), Status::OK), + (hf128!("-0x1p112"), hf128!("-0x1p112"), Status::OK), + ], + ); } } diff --git a/library/compiler-builtins/libm/src/math/rint.rs b/library/compiler-builtins/libm/src/math/rint.rs index b46de6beaac50..0cb0e2d3637d1 100644 --- a/library/compiler-builtins/libm/src/math/rint.rs +++ b/library/compiler-builtins/libm/src/math/rint.rs @@ -87,10 +87,10 @@ mod tests { } #[track_caller] - fn check(cases: &[(F, F, Status)]) { + fn check(f: fn(F) -> F, cases: &[(F, F, Status)]) { for &(x, exp_res, exp_stat) in cases { let FpResult { val, status } = generic::rint_status(x); - assert_biteq!(val, exp_res, "roundeven({x:?}) ({})", Hex(x)); + assert_biteq!(val, exp_res, "generic::rint_status({x:?}) ({})", Hex(x)); assert_eq!( status, exp_stat, @@ -98,44 +98,58 @@ mod tests { Hex(x), Hex(exp_res) ); + let val = f(x); + assert_biteq!(val, exp_res, "rint({x:?}) ({})", Hex(x)); } } #[test] #[cfg(f16_enabled)] fn check_f16() { - check::(&cases!(f16)); - check::(&[ - (hf16!("0x1p10"), hf16!("0x1p10"), Status::OK), - (hf16!("-0x1p10"), hf16!("-0x1p10"), Status::OK), - ]); + check::(rintf16, &cases!(f16)); + check::( + rintf16, + &[ + (hf16!("0x1p10"), hf16!("0x1p10"), Status::OK), + (hf16!("-0x1p10"), hf16!("-0x1p10"), Status::OK), + ], + ); } #[test] fn check_f32() { - check::(&cases!(f32)); - check::(&[ - (hf32!("0x1p23"), hf32!("0x1p23"), Status::OK), - (hf32!("-0x1p23"), hf32!("-0x1p23"), Status::OK), - ]); + check::(rintf, &cases!(f32)); + check::( + rintf, + &[ + (hf32!("0x1p23"), hf32!("0x1p23"), Status::OK), + (hf32!("-0x1p23"), hf32!("-0x1p23"), Status::OK), + ], + ); } #[test] fn check_f64() { - check::(&cases!(f64)); - check::(&[ - (hf64!("0x1p52"), hf64!("0x1p52"), Status::OK), - (hf64!("-0x1p52"), hf64!("-0x1p52"), Status::OK), - ]); + check::(rint, &cases!(f64)); + check::( + rint, + &[ + (hf64!("0x1p52"), hf64!("0x1p52"), Status::OK), + (hf64!("-0x1p52"), hf64!("-0x1p52"), Status::OK), + ], + ); } #[test] #[cfg(f128_enabled)] fn check_f128() { - check::(&cases!(f128)); - check::(&[ - (hf128!("0x1p112"), hf128!("0x1p112"), Status::OK), - (hf128!("-0x1p112"), hf128!("-0x1p112"), Status::OK), - ]); + check::(rintf128, &cases!(f128)); + check::( + rintf128, + &[ + (hf128!("0x1p112"), hf128!("0x1p112"), Status::OK), + (hf128!("-0x1p112"), hf128!("-0x1p112"), Status::OK), + ], + ); } } diff --git a/library/compiler-builtins/libm/src/math/round.rs b/library/compiler-builtins/libm/src/math/round.rs index 34afa375bb31c..091cd801ad6b4 100644 --- a/library/compiler-builtins/libm/src/math/round.rs +++ b/library/compiler-builtins/libm/src/math/round.rs @@ -59,9 +59,11 @@ mod tests { } #[track_caller] - fn check(cases: &[(F, F)]) { + fn check(f: fn(F) -> F, cases: &[(F, F)]) { for &(x, exp_res) in cases { let val = generic::round(x); + assert_biteq!(val, exp_res, "generic::round_status({x:?}) {}", Hex(x)); + let val = f(x); assert_biteq!(val, exp_res, "round({x:?}) {}", Hex(x)); } } @@ -69,38 +71,50 @@ mod tests { #[test] #[cfg(f16_enabled)] fn check_f16() { - check::(&cases!(f16)); - check::(&[ - (hf16!("0x1p10"), hf16!("0x1p10")), - (hf16!("-0x1p10"), hf16!("-0x1p10")), - ]); + check::(roundf16, &cases!(f16)); + check::( + roundf16, + &[ + (hf16!("0x1p10"), hf16!("0x1p10")), + (hf16!("-0x1p10"), hf16!("-0x1p10")), + ], + ); } #[test] fn check_f32() { - check::(&cases!(f32)); - check::(&[ - (hf32!("0x1p23"), hf32!("0x1p23")), - (hf32!("-0x1p23"), hf32!("-0x1p23")), - ]); + check::(roundf, &cases!(f32)); + check::( + roundf, + &[ + (hf32!("0x1p23"), hf32!("0x1p23")), + (hf32!("-0x1p23"), hf32!("-0x1p23")), + ], + ); } #[test] fn check_f64() { - check::(&cases!(f64)); - check::(&[ - (hf64!("0x1p52"), hf64!("0x1p52")), - (hf64!("-0x1p52"), hf64!("-0x1p52")), - ]); + check::(round, &cases!(f64)); + check::( + round, + &[ + (hf64!("0x1p52"), hf64!("0x1p52")), + (hf64!("-0x1p52"), hf64!("-0x1p52")), + ], + ); } #[test] #[cfg(f128_enabled)] fn check_f128() { - check::(&cases!(f128)); - check::(&[ - (hf128!("0x1p112"), hf128!("0x1p112")), - (hf128!("-0x1p112"), hf128!("-0x1p112")), - ]); + check::(roundf128, &cases!(f128)); + check::( + roundf128, + &[ + (hf128!("0x1p112"), hf128!("0x1p112")), + (hf128!("-0x1p112"), hf128!("-0x1p112")), + ], + ); } } diff --git a/library/compiler-builtins/libm/src/math/trunc.rs b/library/compiler-builtins/libm/src/math/trunc.rs index 8dff82e938ece..9eb902ea578f8 100644 --- a/library/compiler-builtins/libm/src/math/trunc.rs +++ b/library/compiler-builtins/libm/src/math/trunc.rs @@ -79,10 +79,10 @@ mod tests { } #[track_caller] - fn check(cases: &[(F, F, Status)]) { + fn check(f: fn(F) -> F, cases: &[(F, F, Status)]) { for &(x, exp_res, exp_stat) in cases { let FpResult { val, status } = generic::trunc_status(x); - assert_biteq!(val, exp_res, "trunc({x:?}) ({})", Hex(x)); + assert_biteq!(val, exp_res, "generic::trunc_status({x:?}) ({})", Hex(x)); assert_eq!( status, exp_stat, @@ -90,44 +90,58 @@ mod tests { Hex(x), Hex(exp_res) ); + let val = f(x); + assert_biteq!(val, exp_res, "trunc({x:?}) ({})", Hex(x)); } } #[test] #[cfg(f16_enabled)] fn check_f16() { - check::(&cases!(f16)); - check::(&[ - (hf16!("0x1p10"), hf16!("0x1p10"), Status::OK), - (hf16!("-0x1p10"), hf16!("-0x1p10"), Status::OK), - ]); + check::(truncf16, &cases!(f16)); + check::( + truncf16, + &[ + (hf16!("0x1p10"), hf16!("0x1p10"), Status::OK), + (hf16!("-0x1p10"), hf16!("-0x1p10"), Status::OK), + ], + ); } #[test] fn check_f32() { - check::(&cases!(f32)); - check::(&[ - (hf32!("0x1p23"), hf32!("0x1p23"), Status::OK), - (hf32!("-0x1p23"), hf32!("-0x1p23"), Status::OK), - ]); + check::(truncf, &cases!(f32)); + check::( + truncf, + &[ + (hf32!("0x1p23"), hf32!("0x1p23"), Status::OK), + (hf32!("-0x1p23"), hf32!("-0x1p23"), Status::OK), + ], + ); } #[test] fn check_f64() { - check::(&cases!(f64)); - check::(&[ - (hf64!("0x1p52"), hf64!("0x1p52"), Status::OK), - (hf64!("-0x1p52"), hf64!("-0x1p52"), Status::OK), - ]); + check::(trunc, &cases!(f64)); + check::( + trunc, + &[ + (hf64!("0x1p52"), hf64!("0x1p52"), Status::OK), + (hf64!("-0x1p52"), hf64!("-0x1p52"), Status::OK), + ], + ); } #[test] #[cfg(f128_enabled)] fn check_f128() { - check::(&cases!(f128)); - check::(&[ - (hf128!("0x1p112"), hf128!("0x1p112"), Status::OK), - (hf128!("-0x1p112"), hf128!("-0x1p112"), Status::OK), - ]); + check::(truncf128, &cases!(f128)); + check::( + truncf128, + &[ + (hf128!("0x1p112"), hf128!("0x1p112"), Status::OK), + (hf128!("-0x1p112"), hf128!("-0x1p112"), Status::OK), + ], + ); } } From 2dc08eaf3d59421b7ae1e4a3350a6441a27d5eb8 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Tue, 31 Mar 2026 02:16:20 -0500 Subject: [PATCH 063/183] hypot: Move the existing implementation to the `approx` module --- library/compiler-builtins/libm/src/math/{ => approx}/hypot.rs | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename library/compiler-builtins/libm/src/math/{ => approx}/hypot.rs (100%) diff --git a/library/compiler-builtins/libm/src/math/hypot.rs b/library/compiler-builtins/libm/src/math/approx/hypot.rs similarity index 100% rename from library/compiler-builtins/libm/src/math/hypot.rs rename to library/compiler-builtins/libm/src/math/approx/hypot.rs From 816765baa0418fbf53767ce56b989f803b8b0e06 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Sun, 20 Apr 2025 03:49:19 +0000 Subject: [PATCH 064/183] hypot: Add cr_hypot from CORE-math Replace our current implementation with one that is correctly rounded. Source: https://gitlab.inria.fr/core-math/core-math/-/blob/93d9f3bab7561cfb62f746f7e70c0888bb5c9a00/src/binary64/hypot/hypot.c --- .../libm-test/src/generate/case_list.rs | 33 +- .../libm-test/src/precision.rs | 3 + .../compiler-builtins/libm/src/math/hypot.rs | 301 ++++++++++++++++++ 3 files changed, 334 insertions(+), 3 deletions(-) create mode 100644 library/compiler-builtins/libm/src/math/hypot.rs diff --git a/library/compiler-builtins/libm-test/src/generate/case_list.rs b/library/compiler-builtins/libm-test/src/generate/case_list.rs index c3dbca1c355da..d3daf86843d17 100644 --- a/library/compiler-builtins/libm-test/src/generate/case_list.rs +++ b/library/compiler-builtins/libm-test/src/generate/case_list.rs @@ -1160,12 +1160,39 @@ fn frexpf128_cases() -> Vec> { cases![] } -fn hypot_cases() -> Vec> { +fn hypotf_cases() -> Vec> { cases![] } -fn hypotf_cases() -> Vec> { - cases![] +fn hypot_cases() -> Vec> { + cases![ + // Cases that can overflow exponent if wrapping arithmetic is not used + ( + ( + hf64!("-0x1.800f800f80100p+1023"), + hf64!("0x1.8354835473720p+996"), + ), + None + ), + ( + (hf64!("0x1.201b201b201c0p+0"), hf64!("0x1.b028b028b02a0p-1")), + None + ), + ( + ( + hf64!("-0x1.e538e538e564p+980"), + hf64!("-0x1.c4dfc4dfc508p+983"), + ), + None + ), + ( + ( + hf64!("-0x1.2f22e4f77aa58p+983"), + hf64!("-0x1.44c9f5524c8ccp+980"), + ), + None + ), + ] } #[cfg(f16_enabled)] diff --git a/library/compiler-builtins/libm-test/src/precision.rs b/library/compiler-builtins/libm-test/src/precision.rs index 64d8cc7f8d277..bc28d970e7642 100644 --- a/library/compiler-builtins/libm-test/src/precision.rs +++ b/library/compiler-builtins/libm-test/src/precision.rs @@ -75,6 +75,7 @@ pub fn default_ulp(ctx: &CheckCtx) -> Option { // Operations that aren't required to be exact, but our implementations are. Bn::Cbrt => 0, + Bn::Hypot if ctx.fn_ident == Id::Hypot => 0, // Bessel functions have large inaccuracies. Bn::J0 | Bn::J1 | Bn::Y0 | Bn::Y1 | Bn::Jn | Bn::Yn => 8_000_000, @@ -143,6 +144,7 @@ pub fn default_ulp(ctx: &CheckCtx) -> Option { Id::Asinh => ulp = 3, Id::Asinhf => ulp = 3, Id::Cbrt => ulp = 1, + Id::Hypot => ulp = 1, Id::Log1p => ulp = 2, Id::Log1pf => ulp = 2, Id::Tan => ulp = 2, @@ -170,6 +172,7 @@ pub fn default_ulp(ctx: &CheckCtx) -> Option { Id::Exp10f if cfg!(x86_no_sse2) => ulp = 4, Id::Exp2f => ulp = 1, Id::Expf => ulp = 1, + Id::Hypot => ulp = 1, Id::Tanh => ulp = 4, Id::Tanhf => ulp = 4, _ => (), diff --git a/library/compiler-builtins/libm/src/math/hypot.rs b/library/compiler-builtins/libm/src/math/hypot.rs new file mode 100644 index 0000000000000..e8bd44ca975d5 --- /dev/null +++ b/library/compiler-builtins/libm/src/math/hypot.rs @@ -0,0 +1,301 @@ +/* SPDX-License-Identifier: MIT */ +/* origin: core-math/src/binary64/hypot/hypot.c + * Copyright (c) 2022 Alexei Sibidanov. + * Ported to Rust in 2025, TG + * Approximate CORE-MATH commit: 8ea8ea35c518 + */ + +//! Euclidian distance via the pythagorean theorem (`√(x2 + y2)`). +//! +//! Per IEEE 754-2019: +//! +//! - Domain: `[−∞, +∞] × [−∞, +∞]` +//! - `hypot(±0, ±0)` is +0 +//! - `hypot(±∞, qNaN)` is +∞ +//! - `hypot(qNaN, ±∞)` is +∞. +//! - May raise overflow or underflow + +use super::sqrt; +#[allow(unused_imports)] // msrv compat +use super::support::Float; +use super::support::cold_path; + +#[cfg_attr(assert_no_panic, no_panic::no_panic)] +pub fn hypot(x: f64, y: f64) -> f64 { + return cr_hypot(x, y); +} + +fn cr_hypot(mut x: f64, mut y: f64) -> f64 { + let flag = get_flags(); + + let xi = x.to_bits(); + let yi = y.to_bits(); + + let emsk: u64 = 0x7ffu64 << 52; + let mut ex: u64 = xi & emsk; + let mut ey: u64 = yi & emsk; + /* emsk corresponds to the upper bits of NaN and Inf (apart the sign bit) */ + x = x.abs(); + y = y.abs(); + if ex == emsk || ey == emsk { + cold_path(); + + /* Either x or y is NaN or Inf */ + let wx: u64 = xi << 1; + let wy: u64 = yi << 1; + let wm: u64 = emsk << 1; + + let one_inf = (wx == wm) ^ (wy == wm); + let one_nan = x.is_nan() ^ y.is_nan(); + + // let nqnn: i32 = (((wx >> 52) == 0xfff) ^ ((wy >> 52) == 0xfff)) as i32; + // /* ninf is 1 when only one of x and y is +/-Inf + // nqnn is 1 when only one of x and y is qNaN + // IEEE 754 says that hypot(+/-Inf,qNaN)=hypot(qNaN,+/-Inf)=+Inf. */ + if one_inf && one_nan { + return f64::INFINITY; + } + return x + y; /* inf, sNaN */ + } + + let u: f64 = x.max(y); + let v: f64 = x.min(y); + let mut xd: u64 = u.to_bits(); + let mut yd: u64 = v.to_bits(); + ey = yd; + + if ey >> 52 == 0 { + cold_path(); + + if yd == 0 { + return f64::from_bits(xd); + } + + ex = xd; + + if ex >> 52 == 0 { + cold_path(); + + if ex == 0 { + return 0.0; + } + + return as_hypot_denorm(ex, ey); + } + + let nz: u32 = ey.leading_zeros(); + ey <<= nz - 11; + ey &= u64::MAX >> 12; + ey = ey.wrapping_sub(((nz as i64 - 12i64) << 52) as u64); + let t = ey; // why did they do this? + yd = t; + } + + let de: u64 = xd.wrapping_sub(yd); + if de > (27_u64 << 52) { + cold_path(); + return hf64!("0x1p-27").fma(v, u); + } + + let off: i64 = (0x3ff_i64 << 52) - (xd & emsk) as i64; + xd = xd.wrapping_add(off as u64); + yd = yd.wrapping_add(off as u64); + x = f64::from_bits(xd); + y = f64::from_bits(yd); + let x2: f64 = x * x; + let dx2: f64 = x.fma(x, -x2); + let y2: f64 = y * y; + let dy2: f64 = y.fma(y, -y2); + let r2: f64 = x2 + y2; + let ir2: f64 = 0.5 / r2; + let dr2: f64 = ((x2 - r2) + y2) + (dx2 + dy2); + let mut th: f64 = sqrt(r2); + let rsqrt: f64 = th * ir2; + let dz: f64 = dr2 - th.fma(th, -r2); + let mut tl: f64 = rsqrt * dz; + th = fasttwosum(th, tl, &mut tl); + let mut thd: u64 = th.to_bits(); + let tld = tl.abs().to_bits(); + ex = thd; + ey = tld; + ex &= 0x7ff_u64 << 52; + let aidr: u64 = ey.wrapping_add(0x3fe_u64 << 52).wrapping_sub(ex); + let mid: u64 = (aidr.wrapping_sub(0x3c90000000000000).wrapping_add(16)) >> 5; + if mid == 0 || !(0x39b0000000000000_u64..=0x3c9fffffffffff80_u64).contains(&aidr) { + cold_path(); + thd = as_hypot_hard(x, y, flag).to_bits(); + } + thd = thd.wrapping_sub(off as u64); + if thd >= (0x7ff_u64 << 52) { + cold_path(); + return as_hypot_overflow(); + } + + f64::from_bits(thd) +} + +fn fasttwosum(x: f64, y: f64, e: &mut f64) -> f64 { + let s: f64 = x + y; + let z: f64 = s - x; + *e = y - z; + s +} + +fn as_hypot_overflow() -> f64 { + let z: f64 = hf64!("0x1.fffffffffffffp1023"); + let f = z + z; + if f > z { + // errno = ERANGE + } + f +} + +/// Here the square root is refined by Newton iterations: x^2+y^2 is exact +/// and fits in a 128-bit integer, so the approximation is squared (which +/// also fits in a 128-bit integer), compared and adjusted if necessary using +/// the exact value of x^2+y^2. +fn as_hypot_hard(x: f64, y: f64, flag: FExcept) -> f64 { + let op: f64 = 1.0 + hf64!("0x1p-54"); + let om: f64 = 1.0 - hf64!("0x1p-54"); + let mut xi: u64 = x.to_bits(); + let yi: u64 = y.to_bits(); + let mut bm: u64 = (xi & (u64::MAX >> 12)) | 1u64 << 52; + let mut lm: u64 = (yi & (u64::MAX >> 12)) | 1u64 << 52; + let be: i32 = (xi >> 52) as i32; + let le: i32 = (yi >> 52) as i32; + let ri: u64 = sqrt(x * x + y * y).to_bits(); + let bs: i32 = 2; + let mut rm: u64 = ri & (u64::MAX >> 12); + let mut re: i32 = (ri >> 52) as i32 - 0x3ff; + rm |= 1u64 << 52; + + for _ in 0..3 { + if rm == 1u64 << 52 { + rm = u64::MAX >> 11; + re -= 1; + } else { + cold_path(); + rm -= 1; + } + } + + bm <<= bs; + let mut m2: u64 = bm.wrapping_mul(bm); + let de: i32 = be - le; + let mut ls: i32 = bs - de; + + if ls >= 0 { + lm <<= ls; + m2 = m2.wrapping_add(lm.wrapping_mul(lm)); + } else { + cold_path(); + let lm2: u128 = (lm as u128) * (lm as u128); + ls *= 2; + m2 = m2.wrapping_add((lm2 >> -ls) as u64); + m2 |= ((lm2 << (128 + ls)) != 0) as u64; + } + + let k: i32 = bs + re; + let mut d: i64; + + loop { + rm += 1 + (rm >= (1u64 << 53)) as u64; + let tm: u64 = rm << k; + let rm2: u64 = tm.wrapping_mul(tm); + d = m2 as i64 - rm2 as i64; + + if d <= 0 { + break; + } + } + + if d == 0 { + set_flags(flag); + } else if op == om { + let tm: u64 = (rm << k) - (1 << (k - (rm <= (1u64 << 53)) as i32)); + d = m2 as i64 - (tm.wrapping_mul(tm)) as i64; + + if d == 0 { + cold_path(); + rm -= rm & 1; + } else { + rm = rm.wrapping_add((d >> 63) as u64); + } + } else { + cold_path(); + rm -= ((op == 1.0) as u64) << (rm > (1u64 << 53)) as u32; + } + + if rm >= (1u64 << 53) { + rm >>= 1; + re += 1; + } + + let e: u64 = (be - 1 + re) as u64; + xi = (e << 52) + rm; + + f64::from_bits(xi) +} + +fn as_hypot_denorm(mut a: u64, mut b: u64) -> f64 { + let op: f64 = 1.0 + hf64!("0x1p-54"); + let om: f64 = 1.0 - hf64!("0x1p-54"); + let af: f64 = a as i64 as f64; + let bf: f64 = b as i64 as f64; + a <<= 1; + b <<= 1; + // Is this casting right? + let mut rm: u64 = sqrt(af * af + bf * bf) as u64; + let tm: u64 = rm << 1; + let mut d: i64 = (a.wrapping_mul(a) as i64) + .wrapping_sub(tm.wrapping_mul(tm) as i64) + .wrapping_add(b.wrapping_mul(b) as i64); + let sd: i64 = d >> 63; + let um: i64 = ((rm as i64) ^ sd) - sd; + let mut drm: i64 = sd + 1; + let mut dd: i64 = (um << 3) + 4; + let mut p_d: i64; + rm -= drm as u64; + drm += sd; + loop { + p_d = d; + rm = rm.wrapping_add(drm as u64); + d = d.wrapping_sub(dd); + dd = dd.wrapping_add(8); + if (d ^ p_d) <= 0 { + cold_path(); + break; + } + } + p_d = (sd & d) + (!sd & p_d); + if p_d != 0 { + if op == om { + let sum: i64 = p_d + .wrapping_sub(4u64.wrapping_mul(rm) as i64) + .wrapping_sub(1); + + if sum != 0 { + rm = rm.wrapping_add((sum >> 63).wrapping_add(1) as u64); + } else { + cold_path(); + rm += rm & 1; + } + } else { + cold_path(); + rm += (op > 1.0) as u64; + } + } else { + cold_path(); + } + + let xi: u64 = rm; + f64::from_bits(xi) +} + +type FExcept = u32; + +fn set_flags(_flag: FExcept) {} + +fn get_flags() -> FExcept { + 0 +} From f9aeb48c513cbcfabb16f7b4e4bebb61b1336c18 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Thu, 12 Feb 2026 03:51:06 -0600 Subject: [PATCH 065/183] libm: Add an `approx` module As we port more correctly rounded implementatinos from CORE-MATH, it would be nice to keep the existing versions around since they are simpler, typically smaller and faster, and easier to port to other float types. The implementations have also been reasonably well tested. Introduce an `approx` module that will serve as a home for these. As the first member, add back the old `cbrt` implementation that was replaced in 75a7f3df3ed7 ("Port the CORE-MATH version of `cbrt`"). --- .../libm/src/math/approx/cbrtf64.rs | 113 ++++++++++++++++++ .../libm/src/math/approx/mod.rs | 8 ++ .../compiler-builtins/libm/src/math/mod.rs | 2 + 3 files changed, 123 insertions(+) create mode 100644 library/compiler-builtins/libm/src/math/approx/cbrtf64.rs create mode 100644 library/compiler-builtins/libm/src/math/approx/mod.rs diff --git a/library/compiler-builtins/libm/src/math/approx/cbrtf64.rs b/library/compiler-builtins/libm/src/math/approx/cbrtf64.rs new file mode 100644 index 0000000000000..7b371feb96b6d --- /dev/null +++ b/library/compiler-builtins/libm/src/math/approx/cbrtf64.rs @@ -0,0 +1,113 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/s_cbrt.c */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + * + * Optimized by Bruce D. Evans. + */ +/* cbrt(x) + * Return cube root of x + */ + +use core::f64; + +const B1: u32 = 715094163; /* B1 = (1023-1023/3-0.03306235651)*2**20 */ +const B2: u32 = 696219795; /* B2 = (1023-1023/3-54/3-0.03306235651)*2**20 */ + +/* |1/cbrt(x) - p(x)| < 2**-23.5 (~[-7.93e-8, 7.929e-8]). */ +const P0: f64 = 1.87595182427177009643; /* 0x3ffe03e6, 0x0f61e692 */ +const P1: f64 = -1.88497979543377169875; /* 0xbffe28e0, 0x92f02420 */ +const P2: f64 = 1.621429720105354466140; /* 0x3ff9f160, 0x4a49d6c2 */ +const P3: f64 = -0.758397934778766047437; /* 0xbfe844cb, 0xbee751d9 */ +const P4: f64 = 0.145996192886612446982; /* 0x3fc2b000, 0xd4e4edd7 */ + +/// Cube root (f64) +/// +/// Computes the cube root of the argument. +#[cfg_attr(assert_no_panic, no_panic::no_panic)] +pub fn cbrtf64(x: f64) -> f64 { + let x1p54 = f64::from_bits(0x4350000000000000); // 0x1p54 === 2 ^ 54 + + let mut ui: u64 = x.to_bits(); + let mut r: f64; + let s: f64; + let mut t: f64; + let w: f64; + let mut hx: u32 = (ui >> 32) as u32 & 0x7fffffff; + + if hx >= 0x7ff00000 { + /* cbrt(NaN,INF) is itself */ + return x + x; + } + + /* + * Rough cbrt to 5 bits: + * cbrt(2**e*(1+m) ~= 2**(e/3)*(1+(e%3+m)/3) + * where e is integral and >= 0, m is real and in [0, 1), and "/" and + * "%" are integer division and modulus with rounding towards minus + * infinity. The RHS is always >= the LHS and has a maximum relative + * error of about 1 in 16. Adding a bias of -0.03306235651 to the + * (e%3+m)/3 term reduces the error to about 1 in 32. With the IEEE + * floating point representation, for finite positive normal values, + * ordinary integer divison of the value in bits magically gives + * almost exactly the RHS of the above provided we first subtract the + * exponent bias (1023 for doubles) and later add it back. We do the + * subtraction virtually to keep e >= 0 so that ordinary integer + * division rounds towards minus infinity; this is also efficient. + */ + if hx < 0x00100000 { + /* zero or subnormal? */ + ui = (x * x1p54).to_bits(); + hx = (ui >> 32) as u32 & 0x7fffffff; + if hx == 0 { + return x; /* cbrt(0) is itself */ + } + hx = hx / 3 + B2; + } else { + hx = hx / 3 + B1; + } + ui &= 1 << 63; + ui |= (hx as u64) << 32; + t = f64::from_bits(ui); + + /* + * New cbrt to 23 bits: + * cbrt(x) = t*cbrt(x/t**3) ~= t*P(t**3/x) + * where P(r) is a polynomial of degree 4 that approximates 1/cbrt(r) + * to within 2**-23.5 when |r - 1| < 1/10. The rough approximation + * has produced t such than |t/cbrt(x) - 1| ~< 1/32, and cubing this + * gives us bounds for r = t**3/x. + * + * Try to optimize for parallel evaluation as in __tanf.c. + */ + r = (t * t) * (t / x); + t = t * ((P0 + r * (P1 + r * P2)) + ((r * r) * r) * (P3 + r * P4)); + + /* + * Round t away from zero to 23 bits (sloppily except for ensuring that + * the result is larger in magnitude than cbrt(x) but not much more than + * 2 23-bit ulps larger). With rounding towards zero, the error bound + * would be ~5/6 instead of ~4/6. With a maximum error of 2 23-bit ulps + * in the rounded t, the infinite-precision error in the Newton + * approximation barely affects third digit in the final error + * 0.667; the error in the rounded t can be up to about 3 23-bit ulps + * before the final error is larger than 0.667 ulps. + */ + ui = t.to_bits(); + ui = (ui + 0x80000000) & 0xffffffffc0000000; + t = f64::from_bits(ui); + + /* one step Newton iteration to 53 bits with error < 0.667 ulps */ + s = t * t; /* t*t is exact */ + r = x / s; /* error <= 0.5 ulps; |r| < |t| */ + w = t + t; /* t+t is exact */ + r = (r - t) / (w + r); /* r-t is exact; w+r ~= 3*t */ + t = t + t * r; /* error <= 0.5 + 0.5/3 + epsilon */ + t +} diff --git a/library/compiler-builtins/libm/src/math/approx/mod.rs b/library/compiler-builtins/libm/src/math/approx/mod.rs new file mode 100644 index 0000000000000..da0d0bf39efc4 --- /dev/null +++ b/library/compiler-builtins/libm/src/math/approx/mod.rs @@ -0,0 +1,8 @@ +//! Approximate implementations. +//! +//! These functions may be smaller or faster than those in the main `math` module, but will +//! not be as accurate. + +mod cbrtf64; + +pub use cbrtf64::cbrtf64; diff --git a/library/compiler-builtins/libm/src/math/mod.rs b/library/compiler-builtins/libm/src/math/mod.rs index 4bee4478164a0..fe9ef580ca679 100644 --- a/library/compiler-builtins/libm/src/math/mod.rs +++ b/library/compiler-builtins/libm/src/math/mod.rs @@ -75,6 +75,8 @@ cfg_if! { } } +pub mod approx; + // Private modules mod arch; mod expo2; From 3f2745ce6e1499423b580ed9162dd7e2fe1fc80b Mon Sep 17 00:00:00 2001 From: Ubiratan Soares Date: Tue, 31 Mar 2026 21:54:57 +0200 Subject: [PATCH 066/183] ci: fix rustc-pull permissions --- .../compiler-builtins/.github/workflows/rustc-pull.yml | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/library/compiler-builtins/.github/workflows/rustc-pull.yml b/library/compiler-builtins/.github/workflows/rustc-pull.yml index 5fc63984b6bc1..7d193eef0a50d 100644 --- a/library/compiler-builtins/.github/workflows/rustc-pull.yml +++ b/library/compiler-builtins/.github/workflows/rustc-pull.yml @@ -1,11 +1,11 @@ # Perform a subtree sync (pull) using the josh-sync tool once every few days (or on demand). name: rustc-pull -permissions: {} + on: workflow_dispatch: schedule: # Run at 04:00 UTC every Monday and Thursday - - cron: '0 4 * * 1,4' + - cron: "0 4 * * 1,4" env: JOSH_SYNC_VERBOSE: true @@ -18,10 +18,13 @@ jobs: github-app-id: ${{ vars.APP_CLIENT_ID }} # https://rust-lang.zulipchat.com/#narrow/channel/219381-t-libs/topic/compiler-builtins.20subtree.20sync.20automation/with/528482375 zulip-stream-id: 219381 - zulip-topic: 'compiler-builtins subtree sync automation' + zulip-topic: "compiler-builtins subtree sync automation" zulip-bot-email: "compiler-builtins-ci-bot@rust-lang.zulipchat.com" pr-base-branch: main branch-name: rustc-pull secrets: zulip-api-token: ${{ secrets.ZULIP_API_TOKEN }} github-app-secret: ${{ secrets.APP_PRIVATE_KEY }} + permissions: + contents: write + pull-requests: write From cf46b0a82c7b80f8c1c2560ecf9dd22832b843ee Mon Sep 17 00:00:00 2001 From: The rustc-josh-sync Cronjob Bot Date: Tue, 31 Mar 2026 20:35:11 +0000 Subject: [PATCH 067/183] Prepare for merging from rust-lang/rust This updates the rust-version file to 0e95a0f4c677002a5d4ac5bc59d97885e6f51f71. --- library/compiler-builtins/rust-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/rust-version b/library/compiler-builtins/rust-version index aa3876b14a221..e98704ad335bd 100644 --- a/library/compiler-builtins/rust-version +++ b/library/compiler-builtins/rust-version @@ -1 +1 @@ -db3e99bbab28c6ca778b13222becdea54533d908 +0e95a0f4c677002a5d4ac5bc59d97885e6f51f71 From 03e408b22b64645c21fe485c6d2a79286c93fd3e Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Tue, 31 Mar 2026 16:47:42 -0400 Subject: [PATCH 068/183] ci: Explicitly set the `compiler-builtins` feature for symcheck Since this is no longer a default feature, we need to enable it to avoid getting errors about symbols from `core`. --- library/compiler-builtins/ci/run.sh | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/library/compiler-builtins/ci/run.sh b/library/compiler-builtins/ci/run.sh index 06e3460380fe4..5ddfbd038f5c5 100755 --- a/library/compiler-builtins/ci/run.sh +++ b/library/compiler-builtins/ci/run.sh @@ -79,12 +79,14 @@ symcheck+=(-- --build-and-check --target "$target") # Executable section checks are meaningless on no-std targets [[ "$target" == *"-none"* ]] && symcheck+=(--no-os) -"${symcheck[@]}" -- -p compiler_builtins -"${symcheck[@]}" -- -p compiler_builtins --release -"${symcheck[@]}" -- -p compiler_builtins --features c -"${symcheck[@]}" -- -p compiler_builtins --features c --release -"${symcheck[@]}" -- -p compiler_builtins --features no-asm -"${symcheck[@]}" -- -p compiler_builtins --features no-asm --release +# We only need to check the configurations std may use +symcheck_cb_args=(-- --package compiler_builtins --features compiler-builtins) +"${symcheck[@]}" "${symcheck_cb_args[@]}" +"${symcheck[@]}" "${symcheck_cb_args[@]}" --release +"${symcheck[@]}" "${symcheck_cb_args[@]}" --features c +"${symcheck[@]}" "${symcheck_cb_args[@]}" --features c --release +"${symcheck[@]}" "${symcheck_cb_args[@]}" --features no-asm +"${symcheck[@]}" "${symcheck_cb_args[@]}" --features no-asm --release run_intrinsics_test() { build_args=(--verbose --manifest-path builtins-test-intrinsics/Cargo.toml) From 0f19a2db1a1dc66ca0aca4471d541f469b09291e Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Tue, 31 Mar 2026 19:06:08 -0400 Subject: [PATCH 069/183] ci: Temporarily disable the RISC-V runners There are a limited amount of runners for these jobs, which is causing a slow point in CI. Once more runners are available we can re-enable the job. --- library/compiler-builtins/.github/workflows/main.yaml | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/library/compiler-builtins/.github/workflows/main.yaml b/library/compiler-builtins/.github/workflows/main.yaml index 57a40d4fd9b29..f90b758536b0d 100644 --- a/library/compiler-builtins/.github/workflows/main.yaml +++ b/library/compiler-builtins/.github/workflows/main.yaml @@ -77,8 +77,9 @@ jobs: os: ubuntu-24.04 - target: powerpc64le-unknown-linux-gnu os: ubuntu-24.04-ppc64le - - target: riscv64gc-unknown-linux-gnu - os: ["self-hosted", "linux", "riscv64"] + # FIXME(ci): re-enable these once more capacity is avialable + # - target: riscv64gc-unknown-linux-gnu + # os: ["self-hosted", "linux", "riscv64"] - target: riscv64gc-unknown-linux-gnu os: ubuntu-24.04 - target: s390x-unknown-linux-gnu From cf6b8b38c02a41212ba469d729ccdbd1774c47a2 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Tue, 31 Mar 2026 18:50:22 -0400 Subject: [PATCH 070/183] ci: Allow both benchmark versions to run on regressions Don't exit immediately if a benchmark has regressions. Instead, save the error and continue with the rest, then exit at the end. --- library/compiler-builtins/ci/bench-icount.sh | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/library/compiler-builtins/ci/bench-icount.sh b/library/compiler-builtins/ci/bench-icount.sh index c7f25dfa18ef6..dcb24428e3915 100755 --- a/library/compiler-builtins/ci/bench-icount.sh +++ b/library/compiler-builtins/ci/bench-icount.sh @@ -26,6 +26,8 @@ tag="$(echo "$target" | cut -d'-' -f1)" # after the first run with gungraun. [ -d "iai-home" ] && mv "iai-home" "$gungraun_home" +failed="0" + # Run benchmarks once function run_icount_benchmarks() { cargo_args=( @@ -66,7 +68,7 @@ function run_icount_benchmarks() { # Disregard regressions after merge echo "Benchmarks completed with regressions; ignoring (not in a PR)" else - ./ci/ci-util.py handle-bench-regressions "$PR_NUMBER" + ./ci/ci-util.py handle-bench-regressions "$PR_NUMBER" || failed="1" fi } @@ -74,6 +76,11 @@ function run_icount_benchmarks() { run_icount_benchmarks --features force-soft-floats -- --save-baseline=softfloat run_icount_benchmarks -- --save-baseline=hardfloat +if [ "$failed" != "0" ]; then + echo "One or more benchmarks failed" + exit 1 +fi + # Name and tar the new baseline name="baseline-icount-$tag-$(date -u +'%Y%m%d%H%M')-${GITHUB_SHA:0:12}" echo "BASELINE_NAME=$name" >>"$GITHUB_ENV" From cb4025be4890042227502f3d2b559779748b56b6 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Tue, 31 Mar 2026 17:56:23 -0400 Subject: [PATCH 071/183] c-b: Remove the `mangled-names` feature from `builtins-test` This isn't used anywhere in CI and there doesn't seem to be a reason that it would need to be toggled. Enable `mangled-names` on the `compiler-builtins` dependency by default and remove the from `builtins-test`. --- library/compiler-builtins/builtins-test/Cargo.toml | 5 ++--- library/compiler-builtins/builtins-test/tests/lse.rs | 2 +- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/library/compiler-builtins/builtins-test/Cargo.toml b/library/compiler-builtins/builtins-test/Cargo.toml index b2313bb9d140e..2cac4385f54ae 100644 --- a/library/compiler-builtins/builtins-test/Cargo.toml +++ b/library/compiler-builtins/builtins-test/Cargo.toml @@ -6,7 +6,7 @@ publish = false license = "MIT AND Apache-2.0 WITH LLVM-exception AND (MIT OR Apache-2.0)" [dependencies] -compiler_builtins = { workspace = true, features = ["unstable-public-internals"] } +compiler_builtins = { workspace = true, features = ["mangled-names", "unstable-public-internals"] } # For fuzzing tests we want a deterministic seedable RNG. We also eliminate potential # problems with system RNGs on the variety of platforms this crate is tested on. @@ -29,11 +29,10 @@ utest-cortex-m-qemu = { default-features = false, git = "https://github.com/japa utest-macros = { git = "https://github.com/japaric/utest" } [features] -default = ["mangled-names"] +default = [] c = ["compiler_builtins/c"] no-asm = ["compiler_builtins/no-asm"] mem = ["compiler_builtins/mem"] -mangled-names = ["compiler_builtins/mangled-names"] # Skip tests that rely on f128 symbols being available on the system no-sys-f128 = ["no-sys-f128-int-convert", "no-sys-f16-f128-convert"] # Some platforms have some f128 functions but everything except integer conversions diff --git a/library/compiler-builtins/builtins-test/tests/lse.rs b/library/compiler-builtins/builtins-test/tests/lse.rs index 7fdc6da8bc25a..20d4d19a328a1 100644 --- a/library/compiler-builtins/builtins-test/tests/lse.rs +++ b/library/compiler-builtins/builtins-test/tests/lse.rs @@ -1,7 +1,7 @@ #![allow(unused_features)] #![feature(decl_macro)] // so we can use pub(super) #![feature(macro_metavar_expr_concat)] -#![cfg(all(target_arch = "aarch64", feature = "mangled-names"))] +#![cfg(target_arch = "aarch64")] use std::sync::Mutex; From ce2542869385111e3c67105995ee4a3cd7ad9e17 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Tue, 31 Mar 2026 18:35:12 -0400 Subject: [PATCH 072/183] c-b: Change the `mangled-names` feature to `unmangled-names` This feature is somewhat backwards because the mangled names are always available; enabling the `mangled-names` feature disables unmangled names. This was likely somehow related to default features when the crate was published on crates.io. Rename the feature and reverse the logic such that unmangled names are exposed when the feature `unmangled-names` is enabled. Note that this changes some benchmarking logic; see the following commit message for details. --- library/compiler-builtins/Cargo.toml | 4 ++-- library/compiler-builtins/builtins-shim/Cargo.toml | 9 +++++---- .../builtins-test-intrinsics/Cargo.toml | 2 +- library/compiler-builtins/builtins-test/Cargo.toml | 2 +- .../compiler-builtins/compiler-builtins/Cargo.toml | 9 +++++---- .../compiler-builtins/compiler-builtins/build.rs | 2 +- .../src/aarch64_outline_atomics.rs | 4 ++-- .../compiler-builtins/compiler-builtins/src/lib.rs | 5 ++++- .../compiler-builtins/src/macros.rs | 14 +++++++------- .../compiler-builtins/src/probestack.rs | 2 +- library/compiler-builtins/libm/Cargo.toml | 2 +- .../libm/src/math/support/float_traits.rs | 8 ++++---- 12 files changed, 34 insertions(+), 29 deletions(-) diff --git a/library/compiler-builtins/Cargo.toml b/library/compiler-builtins/Cargo.toml index 8845f580f8846..478889ab4a633 100644 --- a/library/compiler-builtins/Cargo.toml +++ b/library/compiler-builtins/Cargo.toml @@ -23,8 +23,8 @@ default-members = [ ] exclude = [ - # `builtins-test-intrinsics` needs the feature `compiler-builtins` enabled - # and `mangled-names` disabled, which is the opposite of what is needed for + # `builtins-test-intrinsics` needs the features `compiler-builtins` and + # `unmangled-names` enabled, which is the opposite of what is needed for # other tests, so it makes sense to keep it out of the workspace. "builtins-test-intrinsics", # We test via the `builtins-shim` crate, so exclude the `compiler-builtins` diff --git a/library/compiler-builtins/builtins-shim/Cargo.toml b/library/compiler-builtins/builtins-shim/Cargo.toml index 32b0308a7b3c9..33e909ccce556 100644 --- a/library/compiler-builtins/builtins-shim/Cargo.toml +++ b/library/compiler-builtins/builtins-shim/Cargo.toml @@ -52,14 +52,15 @@ no-asm = [] # Flag this library as the unstable compiler-builtins lib. This must be enabled # when using as `std`'s dependency.' -compiler-builtins = [] +compiler-builtins = ["unmangled-names"] # Generate memory-related intrinsics like memcpy mem = [] -# Mangle all names so this can be linked in with other versions or other -# compiler-rt implementations. Also used for testing -mangled-names = [] +# Enable `no_mangle` symbols so this crate gets used as the runtime intrinsic +# implementation. Leave this disabled for testing to avoid conflicting with +# the system intrinsics. +unmangled-names = [] # This makes certain traits and function specializations public that # are not normally public but are required by the `builtins-test` diff --git a/library/compiler-builtins/builtins-test-intrinsics/Cargo.toml b/library/compiler-builtins/builtins-test-intrinsics/Cargo.toml index e73a1f7b17e5b..623e2e8e067dc 100644 --- a/library/compiler-builtins/builtins-test-intrinsics/Cargo.toml +++ b/library/compiler-builtins/builtins-test-intrinsics/Cargo.toml @@ -6,7 +6,7 @@ publish = false license = "MIT OR Apache-2.0" [dependencies] -compiler_builtins = { path = "../builtins-shim", features = ["compiler-builtins"] } +compiler_builtins = { path = "../builtins-shim", features = ["compiler-builtins", "unmangled-names"] } panic-handler = { path = "../crates/panic-handler" } [features] diff --git a/library/compiler-builtins/builtins-test/Cargo.toml b/library/compiler-builtins/builtins-test/Cargo.toml index 2cac4385f54ae..8318c2344dfec 100644 --- a/library/compiler-builtins/builtins-test/Cargo.toml +++ b/library/compiler-builtins/builtins-test/Cargo.toml @@ -6,7 +6,7 @@ publish = false license = "MIT AND Apache-2.0 WITH LLVM-exception AND (MIT OR Apache-2.0)" [dependencies] -compiler_builtins = { workspace = true, features = ["mangled-names", "unstable-public-internals"] } +compiler_builtins = { workspace = true, features = ["unstable-public-internals"] } # For fuzzing tests we want a deterministic seedable RNG. We also eliminate potential # problems with system RNGs on the variety of platforms this crate is tested on. diff --git a/library/compiler-builtins/compiler-builtins/Cargo.toml b/library/compiler-builtins/compiler-builtins/Cargo.toml index d9acb8341d483..2da517936ee13 100644 --- a/library/compiler-builtins/compiler-builtins/Cargo.toml +++ b/library/compiler-builtins/compiler-builtins/Cargo.toml @@ -47,14 +47,15 @@ no-asm = [] # Flag this library as the unstable compiler-builtins lib. This must be enabled # when using as `std`'s dependency.' -compiler-builtins = ["dep:core"] +compiler-builtins = ["dep:core", "unmangled-names"] # Generate memory-related intrinsics like memcpy mem = [] -# Mangle all names so this can be linked in with other versions or other -# compiler-rt implementations. Also used for testing -mangled-names = [] +# Enable `no_mangle` symbols so this crate gets used as the runtime intrinsic +# implementation. Leave this disabled for testing to avoid conflicting with +# the system intrinsics. +unmangled-names = [] # This makes certain traits and function specializations public that # are not normally public but are required by the `builtins-test` diff --git a/library/compiler-builtins/compiler-builtins/build.rs b/library/compiler-builtins/compiler-builtins/build.rs index 6e1d230e3cd26..7166634260504 100644 --- a/library/compiler-builtins/compiler-builtins/build.rs +++ b/library/compiler-builtins/compiler-builtins/build.rs @@ -63,7 +63,7 @@ fn main() { // mangling names though we assume that we're also in test mode so we don't // build anything and we rely on the upstream implementation of compiler-rt // functions - if !cfg!(feature = "mangled-names") && cfg!(feature = "c") { + if cfg!(feature = "unmangled-names") && cfg!(feature = "c") { // Don't use a C compiler for these targets: // // * nvptx - everything is bitcode, not compatible with mixed C/Rust diff --git a/library/compiler-builtins/compiler-builtins/src/aarch64_outline_atomics.rs b/library/compiler-builtins/compiler-builtins/src/aarch64_outline_atomics.rs index 100b67150772a..367768ecb60d6 100644 --- a/library/compiler-builtins/compiler-builtins/src/aarch64_outline_atomics.rs +++ b/library/compiler-builtins/compiler-builtins/src/aarch64_outline_atomics.rs @@ -35,14 +35,14 @@ intrinsics! { } /// Function to enable/disable LSE. To be used only for testing purposes. -#[cfg(feature = "mangled-names")] +#[cfg(feature = "unstable-public-internals")] pub unsafe fn set_have_lse_atomics(has_lse: bool) { let lse_flag = if has_lse { 1 } else { 0 }; HAVE_LSE_ATOMICS.store(lse_flag, Ordering::Relaxed); } /// Function to obtain whether LSE is enabled or not. To be used only for testing purposes. -#[cfg(feature = "mangled-names")] +#[cfg(feature = "unstable-public-internals")] pub fn get_have_lse_atomics() -> bool { HAVE_LSE_ATOMICS.load(Ordering::Relaxed) != 0 } diff --git a/library/compiler-builtins/compiler-builtins/src/lib.rs b/library/compiler-builtins/compiler-builtins/src/lib.rs index 81e4a31e8e449..9e847206caf19 100644 --- a/library/compiler-builtins/compiler-builtins/src/lib.rs +++ b/library/compiler-builtins/compiler-builtins/src/lib.rs @@ -63,7 +63,10 @@ pub mod aarch64; // in the builtins-test tests. So this is a way of enabling the module during testing. #[cfg(all( target_arch = "aarch64", - any(target_feature = "outline-atomics", feature = "mangled-names") + any( + target_feature = "outline-atomics", + feature = "unstable-public-internals" + ) ))] pub mod aarch64_outline_atomics; diff --git a/library/compiler-builtins/compiler-builtins/src/macros.rs b/library/compiler-builtins/compiler-builtins/src/macros.rs index 203cd0949ac52..255ba78dff1e5 100644 --- a/library/compiler-builtins/compiler-builtins/src/macros.rs +++ b/library/compiler-builtins/compiler-builtins/src/macros.rs @@ -254,7 +254,7 @@ macro_rules! intrinsics { $($body)* } - #[cfg(all(target_vendor = "apple", any(target_arch = "x86", target_arch = "x86_64"), not(feature = "mangled-names")))] + #[cfg(all(target_vendor = "apple", any(target_arch = "x86", target_arch = "x86_64"), feature = "unmangled-names"))] mod $name { #[unsafe(no_mangle)] #[cfg_attr(not(any(all(windows, target_env = "gnu"), target_os = "cygwin")), linkage = "weak")] @@ -290,7 +290,7 @@ macro_rules! intrinsics { $($body)* } - #[cfg(all(target_vendor = "apple", any(target_arch = "x86", target_arch = "x86_64"), not(feature = "mangled-names")))] + #[cfg(all(target_vendor = "apple", any(target_arch = "x86", target_arch = "x86_64"), feature = "unmangled-names"))] mod $name { #[unsafe(no_mangle)] #[cfg_attr(not(any(all(windows, target_env = "gnu"), target_os = "cygwin")), linkage = "weak")] @@ -331,7 +331,7 @@ macro_rules! intrinsics { $($body)* } - #[cfg(all(target_arch = "arm", not(feature = "mangled-names")))] + #[cfg(all(target_arch = "arm", feature = "unmangled-names"))] mod $name { #[unsafe(no_mangle)] #[cfg_attr(not(any(all(windows, target_env = "gnu"), target_os = "cygwin")), linkage = "weak")] @@ -341,7 +341,7 @@ macro_rules! intrinsics { } } - #[cfg(all(target_arch = "arm", not(feature = "mangled-names")))] + #[cfg(all(target_arch = "arm", feature = "unmangled-names"))] mod $alias { #[unsafe(no_mangle)] #[cfg_attr(not(any(all(windows, target_env = "gnu"), target_os = "cygwin")), linkage = "weak")] @@ -407,7 +407,7 @@ macro_rules! intrinsics { $($body)* } - #[cfg(all(feature = "mem", not(feature = "mangled-names")))] + #[cfg(all(feature = "mem", feature = "unmangled-names"))] mod $name { $(#[$($attr)*])* #[unsafe(no_mangle)] @@ -435,7 +435,7 @@ macro_rules! intrinsics { pub mod $name { #[unsafe(naked)] $(#[$($attr)*])* - #[cfg_attr(not(feature = "mangled-names"), unsafe(no_mangle))] + #[cfg_attr(feature = "unmangled-names", unsafe(no_mangle))] #[cfg_attr(not(any(all(windows, target_env = "gnu"), target_os = "cygwin")), linkage = "weak")] pub unsafe extern $abi fn $name( $($argname: $ty),* ) $(-> $ret)? { $($body)* @@ -470,7 +470,7 @@ macro_rules! intrinsics { $($body)* } - #[cfg(not(feature = "mangled-names"))] + #[cfg(feature = "unmangled-names")] mod $name { $(#[$($attr)*])* #[unsafe(no_mangle)] diff --git a/library/compiler-builtins/compiler-builtins/src/probestack.rs b/library/compiler-builtins/compiler-builtins/src/probestack.rs index 1cab64ea113c5..c4a2eeb0e0178 100644 --- a/library/compiler-builtins/compiler-builtins/src/probestack.rs +++ b/library/compiler-builtins/compiler-builtins/src/probestack.rs @@ -41,7 +41,7 @@ //! probes on any other architecture like ARM or PowerPC64. LLVM I'm sure would //! be more than welcome to accept such a change! -#![cfg(not(feature = "mangled-names"))] +#![cfg(feature = "unmangled-names")] // Windows and Cygwin already has builtins to do this. #![cfg(not(any(windows, target_os = "cygwin")))] // We only define stack probing for these architectures today. diff --git a/library/compiler-builtins/libm/Cargo.toml b/library/compiler-builtins/libm/Cargo.toml index f87e7a4282415..c5d565736bc3b 100644 --- a/library/compiler-builtins/libm/Cargo.toml +++ b/library/compiler-builtins/libm/Cargo.toml @@ -50,5 +50,5 @@ force-soft-floats = [] unexpected_cfgs = { level = "warn", check-cfg = [ # compiler-builtins sets these features, but we use them in `libm` 'cfg(feature, values("compiler-builtins"))', - 'cfg(feature, values("mangled-names"))', + 'cfg(feature, values("unmangled-names"))', ] } diff --git a/library/compiler-builtins/libm/src/math/support/float_traits.rs b/library/compiler-builtins/libm/src/math/support/float_traits.rs index 208619e358fc3..ad9ddb5ea46ac 100644 --- a/library/compiler-builtins/libm/src/math/support/float_traits.rs +++ b/library/compiler-builtins/libm/src/math/support/float_traits.rs @@ -301,15 +301,15 @@ macro_rules! float_impl { } fn eq_repr(self, rhs: Self) -> bool { - #[cfg(feature = "mangled-names")] + #[cfg(not(feature = "unmangled-names"))] fn is_nan(x: $ty) -> bool { - // When using mangled-names, the "real" compiler-builtins might not have the - // necessary builtin (__unordtf2) to test whether `f128` is NaN. + // When not using unmangled-names, the "real" compiler-builtins might not have + // the necessary builtin (__unordtf2) to test whether `f128` is NaN. // FIXME(f128): Remove once the nightly toolchain has the __unordtf2 builtin // x is NaN if all the bits of the exponent are set and the significand is non-0 x.to_bits() & $ty::EXP_MASK == $ty::EXP_MASK && x.to_bits() & $ty::SIG_MASK != 0 } - #[cfg(not(feature = "mangled-names"))] + #[cfg(feature = "unmangled-names")] fn is_nan(x: $ty) -> bool { x.is_nan() } From 9a7c3e1607c12e0ef81bd65c96b1ca4db26c5410 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Tue, 31 Mar 2026 18:45:24 -0400 Subject: [PATCH 073/183] bench: Enable unmangled-names when running benchmarks Ensure that our compiler-builtins is providing the runtime, so we can see the effect of changes in c-b on libm functions. This was happening implicitly before because the `mangled-names` feature was not enabled in tests, so unmangled names were exposed. In commit "c-b: Change the `mangled-names` feature to `unmangled-names`" things were reversed, meaning the unmangled names are no longer exposed by default, so our benches started using the platform symbols. (Hence apparent regressions in fmaf128, ldexpf128, powif128, and scalbnf128). --- library/compiler-builtins/ci/bench-icount.sh | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/library/compiler-builtins/ci/bench-icount.sh b/library/compiler-builtins/ci/bench-icount.sh index dcb24428e3915..e24a47fe07be7 100755 --- a/library/compiler-builtins/ci/bench-icount.sh +++ b/library/compiler-builtins/ci/bench-icount.sh @@ -35,6 +35,11 @@ function run_icount_benchmarks() { "--bench" "*icount*" "--no-default-features" "--features" "unstable,unstable-float,icount" + # Enable unmangled-names so our compiler-builtins gets used for + # intrinsics. This makes performance impacts of c-b changes show up + # in libm benchmarks and gives us a better idea of what will happen + # in std (e.g. speedups in __addtf3 will show up in fmaf128). + "--features" "compiler_builtins/unmangled-names" ) gungraun_args=( From 22579364d8bf45e72f482e85ae3f94159b8bb1c6 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Tue, 31 Mar 2026 19:35:06 -0400 Subject: [PATCH 074/183] c-b: Clean up the `mem` feature `mem` only enables the unmangled names; the functions are always available via mangled names, so this doesn't have any purpose in our tests. Thus, remove it from `builtins-test`. The remaining `feature = "mem"` configuration in tests is for the `aeabi_mem*` files, which call the compiler-builtins functions via extern definitions. Move these to builtins-test-intrinsics, which is the home of other tests that require unmangled symbols. Unfortunately these tests have apparently not worked for a long time; this situation is unchanged. --- library/compiler-builtins/Cargo.lock | 27 ------------------- .../builtins-shim/Cargo.toml | 3 ++- .../builtins-test-intrinsics/Cargo.toml | 6 +++++ .../builtins-test-intrinsics/src/main.rs | 10 ++++--- .../tests/aeabi_memclr.rs | 1 - .../tests/aeabi_memcpy.rs | 1 - .../tests/aeabi_memset.rs | 1 - .../builtins-test/Cargo.toml | 6 ----- .../compiler-builtins/Cargo.toml | 4 +-- .../compiler-builtins/src/macros.rs | 2 +- 10 files changed, 17 insertions(+), 44 deletions(-) rename library/compiler-builtins/{builtins-test => builtins-test-intrinsics}/tests/aeabi_memclr.rs (98%) rename library/compiler-builtins/{builtins-test => builtins-test-intrinsics}/tests/aeabi_memcpy.rs (98%) rename library/compiler-builtins/{builtins-test => builtins-test-intrinsics}/tests/aeabi_memset.rs (99%) diff --git a/library/compiler-builtins/Cargo.lock b/library/compiler-builtins/Cargo.lock index 274084fb4d64f..372e7e68f5fbf 100644 --- a/library/compiler-builtins/Cargo.lock +++ b/library/compiler-builtins/Cargo.lock @@ -155,9 +155,6 @@ dependencies = [ "paste", "rand_xoshiro", "rustc_apfloat", - "test", - "utest-cortex-m-qemu", - "utest-macros", ] [[package]] @@ -1084,12 +1081,6 @@ dependencies = [ "winapi-util", ] -[[package]] -name = "sc" -version = "0.2.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "010e18bd3bfd1d45a7e666b236c78720df0d9a7698ebaa9c1c559961eb60a38b" - [[package]] name = "semver" version = "1.0.27" @@ -1206,11 +1197,6 @@ version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8f50febec83f5ee1df3015341d8bd429f2d1cc62bcba7ea2076759d315084683" -[[package]] -name = "test" -version = "0.1.0" -source = "git+https://github.com/japaric/utest#e32073e2b078e3bee46001c13ae4c1acf368d762" - [[package]] name = "tinytemplate" version = "1.2.1" @@ -1251,19 +1237,6 @@ version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "81e544489bf3d8ef66c953931f56617f423cd4b5494be343d9b9d3dda037b9a3" -[[package]] -name = "utest-cortex-m-qemu" -version = "0.1.0" -source = "git+https://github.com/japaric/utest#e32073e2b078e3bee46001c13ae4c1acf368d762" -dependencies = [ - "sc", -] - -[[package]] -name = "utest-macros" -version = "0.1.0" -source = "git+https://github.com/japaric/utest#e32073e2b078e3bee46001c13ae4c1acf368d762" - [[package]] name = "utf8parse" version = "0.2.2" diff --git a/library/compiler-builtins/builtins-shim/Cargo.toml b/library/compiler-builtins/builtins-shim/Cargo.toml index 33e909ccce556..0ff2acdbbe6a2 100644 --- a/library/compiler-builtins/builtins-shim/Cargo.toml +++ b/library/compiler-builtins/builtins-shim/Cargo.toml @@ -54,7 +54,8 @@ no-asm = [] # when using as `std`'s dependency.' compiler-builtins = ["unmangled-names"] -# Generate memory-related intrinsics like memcpy +# Enable `no_mangle` symbols for memory-related intrinsics like memcpy. The +# mangled versions are always available. mem = [] # Enable `no_mangle` symbols so this crate gets used as the runtime intrinsic diff --git a/library/compiler-builtins/builtins-test-intrinsics/Cargo.toml b/library/compiler-builtins/builtins-test-intrinsics/Cargo.toml index 623e2e8e067dc..fed2ac39fb321 100644 --- a/library/compiler-builtins/builtins-test-intrinsics/Cargo.toml +++ b/library/compiler-builtins/builtins-test-intrinsics/Cargo.toml @@ -6,9 +6,15 @@ publish = false license = "MIT OR Apache-2.0" [dependencies] +# FIXME: `aeabi_mem*` tests will require the "mem" feature to be enabled here. compiler_builtins = { path = "../builtins-shim", features = ["compiler-builtins", "unmangled-names"] } panic-handler = { path = "../crates/panic-handler" } +[target.'cfg(all(target_arch = "arm", not(any(target_env = "gnu", target_env = "musl")), target_os = "linux"))'.dev-dependencies] +test = { git = "https://github.com/japaric/utest" } +utest-cortex-m-qemu = { default-features = false, git = "https://github.com/japaric/utest" } +utest-macros = { git = "https://github.com/japaric/utest" } + [features] c = ["compiler_builtins/c"] diff --git a/library/compiler-builtins/builtins-test-intrinsics/src/main.rs b/library/compiler-builtins/builtins-test-intrinsics/src/main.rs index a3df2c98376cb..e390590946f4c 100644 --- a/library/compiler-builtins/builtins-test-intrinsics/src/main.rs +++ b/library/compiler-builtins/builtins-test-intrinsics/src/main.rs @@ -1,7 +1,9 @@ -// By compiling this file we check that all the intrinsics we care about continue to be provided by -// the `compiler_builtins` crate regardless of the changes we make to it. If we, by mistake, stop -// compiling a C implementation and forget to implement that intrinsic in Rust, this file will fail -// to link due to the missing intrinsic (symbol). +//! Tests that require unmangled symbols from `compiler-builtins`. +//! +//! By compiling this file we check that all the intrinsics we care about continue to be provided by +//! the `compiler_builtins` crate regardless of the changes we make to it. If we, by mistake, stop +//! compiling a C implementation and forget to implement that intrinsic in Rust, this file will fail +//! to link due to the missing intrinsic (symbol). #![allow(internal_features, unused_features)] #![deny(dead_code)] diff --git a/library/compiler-builtins/builtins-test/tests/aeabi_memclr.rs b/library/compiler-builtins/builtins-test-intrinsics/tests/aeabi_memclr.rs similarity index 98% rename from library/compiler-builtins/builtins-test/tests/aeabi_memclr.rs rename to library/compiler-builtins/builtins-test-intrinsics/tests/aeabi_memclr.rs index 0761feaffd9e2..df0e6a6d52997 100644 --- a/library/compiler-builtins/builtins-test/tests/aeabi_memclr.rs +++ b/library/compiler-builtins/builtins-test-intrinsics/tests/aeabi_memclr.rs @@ -2,7 +2,6 @@ target_arch = "arm", not(any(target_env = "gnu", target_env = "musl")), target_os = "linux", - feature = "mem" ))] #![feature(compiler_builtins_lib)] #![no_std] diff --git a/library/compiler-builtins/builtins-test/tests/aeabi_memcpy.rs b/library/compiler-builtins/builtins-test-intrinsics/tests/aeabi_memcpy.rs similarity index 98% rename from library/compiler-builtins/builtins-test/tests/aeabi_memcpy.rs rename to library/compiler-builtins/builtins-test-intrinsics/tests/aeabi_memcpy.rs index e76e712a246f1..acd12eef64ba5 100644 --- a/library/compiler-builtins/builtins-test/tests/aeabi_memcpy.rs +++ b/library/compiler-builtins/builtins-test-intrinsics/tests/aeabi_memcpy.rs @@ -2,7 +2,6 @@ target_arch = "arm", not(any(target_env = "gnu", target_env = "musl")), target_os = "linux", - feature = "mem" ))] #![feature(compiler_builtins_lib)] #![no_std] diff --git a/library/compiler-builtins/builtins-test/tests/aeabi_memset.rs b/library/compiler-builtins/builtins-test-intrinsics/tests/aeabi_memset.rs similarity index 99% rename from library/compiler-builtins/builtins-test/tests/aeabi_memset.rs rename to library/compiler-builtins/builtins-test-intrinsics/tests/aeabi_memset.rs index 8f9f80f969ccb..98d2c6852d14f 100644 --- a/library/compiler-builtins/builtins-test/tests/aeabi_memset.rs +++ b/library/compiler-builtins/builtins-test-intrinsics/tests/aeabi_memset.rs @@ -2,7 +2,6 @@ target_arch = "arm", not(any(target_env = "gnu", target_env = "musl")), target_os = "linux", - feature = "mem" ))] #![feature(compiler_builtins_lib)] #![no_std] diff --git a/library/compiler-builtins/builtins-test/Cargo.toml b/library/compiler-builtins/builtins-test/Cargo.toml index 8318c2344dfec..7f8584286d053 100644 --- a/library/compiler-builtins/builtins-test/Cargo.toml +++ b/library/compiler-builtins/builtins-test/Cargo.toml @@ -23,16 +23,10 @@ gungraun = { workspace = true, optional = true } [dev-dependencies] paste.workspace = true -[target.'cfg(all(target_arch = "arm", not(any(target_env = "gnu", target_env = "musl")), target_os = "linux"))'.dev-dependencies] -test = { git = "https://github.com/japaric/utest" } -utest-cortex-m-qemu = { default-features = false, git = "https://github.com/japaric/utest" } -utest-macros = { git = "https://github.com/japaric/utest" } - [features] default = [] c = ["compiler_builtins/c"] no-asm = ["compiler_builtins/no-asm"] -mem = ["compiler_builtins/mem"] # Skip tests that rely on f128 symbols being available on the system no-sys-f128 = ["no-sys-f128-int-convert", "no-sys-f16-f128-convert"] # Some platforms have some f128 functions but everything except integer conversions diff --git a/library/compiler-builtins/compiler-builtins/Cargo.toml b/library/compiler-builtins/compiler-builtins/Cargo.toml index 2da517936ee13..2299ae8e3aaf3 100644 --- a/library/compiler-builtins/compiler-builtins/Cargo.toml +++ b/library/compiler-builtins/compiler-builtins/Cargo.toml @@ -49,8 +49,8 @@ no-asm = [] # when using as `std`'s dependency.' compiler-builtins = ["dep:core", "unmangled-names"] -# Generate memory-related intrinsics like memcpy -mem = [] +# Enable `no_mangle` symbols for memory-related intrinsics like memcpy. The +# mangled versions are always available. # Enable `no_mangle` symbols so this crate gets used as the runtime intrinsic # implementation. Leave this disabled for testing to avoid conflicting with diff --git a/library/compiler-builtins/compiler-builtins/src/macros.rs b/library/compiler-builtins/compiler-builtins/src/macros.rs index 255ba78dff1e5..c5e49f7780641 100644 --- a/library/compiler-builtins/compiler-builtins/src/macros.rs +++ b/library/compiler-builtins/compiler-builtins/src/macros.rs @@ -392,7 +392,7 @@ macro_rules! intrinsics { intrinsics!($($rest)*); ); - // C mem* functions are only generated when the "mem" feature is enabled. + // C mem* functions are only exposed via `no_mangle` when the "mem" feature is enabled. ( #[mem_builtin] $(#[$($attr:tt)*])* From ed1274749dcf74dfdcdbfd61a58b7bf661b0ff49 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Tue, 31 Mar 2026 20:44:51 -0400 Subject: [PATCH 075/183] test: Turn `feature = "no-sys-f128"` and similar into plain cfg These are internal configuration that Cargo doesn't need to be aware of. Clean them up from the Cargo.toml feature list. --- .../builtins-test/Cargo.toml | 8 -- .../builtins-test/benches/float_add.rs | 2 +- .../builtins-test/benches/float_cmp.rs | 4 +- .../builtins-test/benches/float_conv.rs | 24 +++--- .../builtins-test/benches/float_div.rs | 2 +- .../builtins-test/benches/float_extend.rs | 10 +-- .../builtins-test/benches/float_mul.rs | 2 +- .../builtins-test/benches/float_pow.rs | 6 +- .../builtins-test/benches/float_sub.rs | 2 +- .../builtins-test/benches/float_trunc.rs | 10 +-- .../compiler-builtins/builtins-test/build.rs | 74 +++++++++++-------- .../builtins-test/tests/addsub.rs | 4 +- .../builtins-test/tests/cmp.rs | 6 +- .../builtins-test/tests/conv.rs | 38 +++++----- .../builtins-test/tests/div_rem.rs | 4 +- .../builtins-test/tests/float_pow.rs | 4 +- .../builtins-test/tests/mul.rs | 4 +- 17 files changed, 106 insertions(+), 98 deletions(-) diff --git a/library/compiler-builtins/builtins-test/Cargo.toml b/library/compiler-builtins/builtins-test/Cargo.toml index 7f8584286d053..1b356b102c19d 100644 --- a/library/compiler-builtins/builtins-test/Cargo.toml +++ b/library/compiler-builtins/builtins-test/Cargo.toml @@ -27,14 +27,6 @@ paste.workspace = true default = [] c = ["compiler_builtins/c"] no-asm = ["compiler_builtins/no-asm"] -# Skip tests that rely on f128 symbols being available on the system -no-sys-f128 = ["no-sys-f128-int-convert", "no-sys-f16-f128-convert"] -# Some platforms have some f128 functions but everything except integer conversions -no-sys-f128-int-convert = [] -no-sys-f16-f128-convert = [] -no-sys-f16-f64-convert = [] -# Skip tests that rely on f16 symbols being available on the system -no-sys-f16 = ["no-sys-f16-f64-convert"] # Enable icount benchmarks (requires gungraun-runner and valgrind locally) icount = ["dep:gungraun"] diff --git a/library/compiler-builtins/builtins-test/benches/float_add.rs b/library/compiler-builtins/builtins-test/benches/float_add.rs index 197f90b319da4..2c1d2d9f15520 100644 --- a/library/compiler-builtins/builtins-test/benches/float_add.rs +++ b/library/compiler-builtins/builtins-test/benches/float_add.rs @@ -74,7 +74,7 @@ float_bench! { crate_fn_ppc: add::__addkf3, sys_fn: __addtf3, sys_fn_ppc: __addkf3, - sys_available: not(feature = "no-sys-f128"), + sys_available: not(no_sys_f128), asm: [] } diff --git a/library/compiler-builtins/builtins-test/benches/float_cmp.rs b/library/compiler-builtins/builtins-test/benches/float_cmp.rs index da29b5d313263..cb13ce18fe4c6 100644 --- a/library/compiler-builtins/builtins-test/benches/float_cmp.rs +++ b/library/compiler-builtins/builtins-test/benches/float_cmp.rs @@ -185,7 +185,7 @@ float_bench! { crate_fn_ppc: cmp::__gtkf2, sys_fn: __gttf2, sys_fn_ppc: __gtkf2, - sys_available: not(feature = "no-sys-f128"), + sys_available: not(no_sys_f128), output_eq: gt_res_eq, asm: [] } @@ -198,7 +198,7 @@ float_bench! { crate_fn_ppc: cmp::__unordkf2, sys_fn: __unordtf2, sys_fn_ppc: __unordkf2, - sys_available: not(feature = "no-sys-f128"), + sys_available: not(no_sys_f128), asm: [] } diff --git a/library/compiler-builtins/builtins-test/benches/float_conv.rs b/library/compiler-builtins/builtins-test/benches/float_conv.rs index 40c13d270ac8e..35255645b2464 100644 --- a/library/compiler-builtins/builtins-test/benches/float_conv.rs +++ b/library/compiler-builtins/builtins-test/benches/float_conv.rs @@ -84,7 +84,7 @@ float_bench! { crate_fn_ppc: conv::__floatunsikf, sys_fn: __floatunsitf, sys_fn_ppc: __floatunsikf, - sys_available: not(feature = "no-sys-f16-f128-convert"), + sys_available: not(no_sys_f16_f128_convert), asm: [] } @@ -138,7 +138,7 @@ float_bench! { crate_fn_ppc: conv::__floatundikf, sys_fn: __floatunditf, sys_fn_ppc: __floatundikf, - sys_available: not(feature = "no-sys-f16-f128-convert"), + sys_available: not(no_sys_f16_f128_convert), asm: [] } @@ -168,7 +168,7 @@ float_bench! { crate_fn_ppc: conv::__floatuntikf, sys_fn: __floatuntitf, sys_fn_ppc: __floatuntikf, - sys_available: not(feature = "no-sys-f16-f128-convert"), + sys_available: not(no_sys_f16_f128_convert), asm: [] } @@ -249,7 +249,7 @@ float_bench! { crate_fn_ppc: conv::__floatsikf, sys_fn: __floatsitf, sys_fn_ppc: __floatsikf, - sys_available: not(feature = "no-sys-f16-f128-convert"), + sys_available: not(no_sys_f16_f128_convert), asm: [] } @@ -328,7 +328,7 @@ float_bench! { crate_fn_ppc: conv::__floatdikf, sys_fn: __floatditf, sys_fn_ppc: __floatdikf, - sys_available: not(feature = "no-sys-f16-f128-convert"), + sys_available: not(no_sys_f16_f128_convert), asm: [] } @@ -358,7 +358,7 @@ float_bench! { crate_fn_ppc: conv::__floattikf, sys_fn: __floattitf, sys_fn_ppc: __floattikf, - sys_available: not(feature = "no-sys-f16-f128-convert"), + sys_available: not(no_sys_f16_f128_convert), asm: [] } @@ -473,7 +473,7 @@ float_bench! { crate_fn: conv::__fixunstfsi, crate_fn_ppc: conv::__fixunskfsi, sys_fn: __fixunstfsi, - sys_available: not(feature = "no-sys-f16-f128-convert"), + sys_available: not(no_sys_f16_f128_convert), asm: [] } @@ -484,7 +484,7 @@ float_bench! { crate_fn: conv::__fixunstfdi, crate_fn_ppc: conv::__fixunskfdi, sys_fn: __fixunstfdi, - sys_available: not(feature = "no-sys-f16-f128-convert"), + sys_available: not(no_sys_f16_f128_convert), asm: [] } @@ -495,7 +495,7 @@ float_bench! { crate_fn: conv::__fixunstfti, crate_fn_ppc: conv::__fixunskfti, sys_fn: __fixunstfti, - sys_available: not(feature = "no-sys-f16-f128-convert"), + sys_available: not(no_sys_f16_f128_convert), asm: [] } @@ -610,7 +610,7 @@ float_bench! { crate_fn: conv::__fixtfsi, crate_fn_ppc: conv::__fixkfsi, sys_fn: __fixtfsi, - sys_available: not(feature = "no-sys-f16-f128-convert"), + sys_available: not(no_sys_f16_f128_convert), asm: [] } @@ -621,7 +621,7 @@ float_bench! { crate_fn: conv::__fixtfdi, crate_fn_ppc: conv::__fixkfdi, sys_fn: __fixtfdi, - sys_available: not(feature = "no-sys-f16-f128-convert"), + sys_available: not(no_sys_f16_f128_convert), asm: [] } @@ -632,7 +632,7 @@ float_bench! { crate_fn: conv::__fixtfti, crate_fn_ppc: conv::__fixkfti, sys_fn: __fixtfti, - sys_available: not(feature = "no-sys-f16-f128-convert"), + sys_available: not(no_sys_f16_f128_convert), asm: [] } diff --git a/library/compiler-builtins/builtins-test/benches/float_div.rs b/library/compiler-builtins/builtins-test/benches/float_div.rs index d5b0ad0fd402b..dd2b2c1f940e2 100644 --- a/library/compiler-builtins/builtins-test/benches/float_div.rs +++ b/library/compiler-builtins/builtins-test/benches/float_div.rs @@ -74,7 +74,7 @@ float_bench! { crate_fn_ppc: div::__divkf3, sys_fn: __divtf3, sys_fn_ppc: __divkf3, - sys_available: not(feature = "no-sys-f128"), + sys_available: not(no_sys_f128), asm: [] } diff --git a/library/compiler-builtins/builtins-test/benches/float_extend.rs b/library/compiler-builtins/builtins-test/benches/float_extend.rs index 939dc60f95f4a..7896d10c8d1aa 100644 --- a/library/compiler-builtins/builtins-test/benches/float_extend.rs +++ b/library/compiler-builtins/builtins-test/benches/float_extend.rs @@ -12,7 +12,7 @@ float_bench! { sig: (a: f16) -> f32, crate_fn: extend::__extendhfsf2, sys_fn: __extendhfsf2, - sys_available: not(feature = "no-sys-f16"), + sys_available: not(no_sys_f16), asm: [ #[cfg(target_arch = "aarch64")] { let ret: f32; @@ -34,7 +34,7 @@ float_bench! { sig: (a: f16) -> f64, crate_fn: extend::__extendhfdf2, sys_fn: __extendhfdf2, - sys_available: not(feature = "no-sys-f16-f64-convert"), + sys_available: not(no_sys_f16_f64_convert), asm: [ #[cfg(target_arch = "aarch64")] { let ret: f64; @@ -58,7 +58,7 @@ float_bench! { crate_fn_ppc: extend::__extendhfkf2, sys_fn: __extendhftf2, sys_fn_ppc: __extendhfkf2, - sys_available: not(feature = "no-sys-f16-f128-convert"), + sys_available: not(no_sys_f16_f128_convert), asm: [], } @@ -91,7 +91,7 @@ float_bench! { crate_fn_ppc: extend::__extendsfkf2, sys_fn: __extendsftf2, sys_fn_ppc: __extendsfkf2, - sys_available: not(feature = "no-sys-f128"), + sys_available: not(no_sys_f128), asm: [], } @@ -103,7 +103,7 @@ float_bench! { crate_fn_ppc: extend::__extenddfkf2, sys_fn: __extenddftf2, sys_fn_ppc: __extenddfkf2, - sys_available: not(feature = "no-sys-f128"), + sys_available: not(no_sys_f128), asm: [], } diff --git a/library/compiler-builtins/builtins-test/benches/float_mul.rs b/library/compiler-builtins/builtins-test/benches/float_mul.rs index a7a2d34aa0489..54fc6daa9b2a6 100644 --- a/library/compiler-builtins/builtins-test/benches/float_mul.rs +++ b/library/compiler-builtins/builtins-test/benches/float_mul.rs @@ -74,7 +74,7 @@ float_bench! { crate_fn_ppc: mul::__mulkf3, sys_fn: __multf3, sys_fn_ppc: __mulkf3, - sys_available: not(feature = "no-sys-f128"), + sys_available: not(no_sys_f128), asm: [] } diff --git a/library/compiler-builtins/builtins-test/benches/float_pow.rs b/library/compiler-builtins/builtins-test/benches/float_pow.rs index 64e37dd32416e..d749ae47ddafb 100644 --- a/library/compiler-builtins/builtins-test/benches/float_pow.rs +++ b/library/compiler-builtins/builtins-test/benches/float_pow.rs @@ -24,7 +24,7 @@ float_bench! { // FIXME(f16_f128): can be changed to only `f128_enabled` once `__multf3` and `__divtf3` are // distributed by nightly. -#[cfg(all(f128_enabled, not(feature = "no-sys-f128")))] +#[cfg(all(f128_enabled, not(no_sys_f128)))] float_bench! { name: powi_f128, sig: (a: f128, b: i32) -> f128, @@ -32,7 +32,7 @@ float_bench! { crate_fn_ppc: pow::__powikf2, sys_fn: __powitf2, sys_fn_ppc: __powikf2, - sys_available: not(feature = "no-sys-f128"), + sys_available: not(no_sys_f128), asm: [] } @@ -42,7 +42,7 @@ pub fn float_pow() { powi_f32(&mut criterion); powi_f64(&mut criterion); - #[cfg(all(f128_enabled, not(feature = "no-sys-f128")))] + #[cfg(all(f128_enabled, not(no_sys_f128)))] powi_f128(&mut criterion); } diff --git a/library/compiler-builtins/builtins-test/benches/float_sub.rs b/library/compiler-builtins/builtins-test/benches/float_sub.rs index 8bae294cd56b1..a8b73d7c7719e 100644 --- a/library/compiler-builtins/builtins-test/benches/float_sub.rs +++ b/library/compiler-builtins/builtins-test/benches/float_sub.rs @@ -74,7 +74,7 @@ float_bench! { crate_fn_ppc: sub::__subkf3, sys_fn: __subtf3, sys_fn_ppc: __subkf3, - sys_available: not(feature = "no-sys-f128"), + sys_available: not(no_sys_f128), asm: [] } diff --git a/library/compiler-builtins/builtins-test/benches/float_trunc.rs b/library/compiler-builtins/builtins-test/benches/float_trunc.rs index 9373f945bb2b8..fdf96fd3d34a4 100644 --- a/library/compiler-builtins/builtins-test/benches/float_trunc.rs +++ b/library/compiler-builtins/builtins-test/benches/float_trunc.rs @@ -11,7 +11,7 @@ float_bench! { sig: (a: f32) -> f16, crate_fn: trunc::__truncsfhf2, sys_fn: __truncsfhf2, - sys_available: not(feature = "no-sys-f16"), + sys_available: not(no_sys_f16), asm: [ #[cfg(target_arch = "aarch64")] { let ret: f16; @@ -33,7 +33,7 @@ float_bench! { sig: (a: f64) -> f16, crate_fn: trunc::__truncdfhf2, sys_fn: __truncdfhf2, - sys_available: not(feature = "no-sys-f16-f64-convert"), + sys_available: not(no_sys_f16_f64_convert), asm: [ #[cfg(target_arch = "aarch64")] { let ret: f16; @@ -90,7 +90,7 @@ float_bench! { crate_fn_ppc: trunc::__trunckfhf2, sys_fn: __trunctfhf2, sys_fn_ppc: __trunckfhf2, - sys_available: not(feature = "no-sys-f16-f128-convert"), + sys_available: not(no_sys_f16_f128_convert), asm: [], } @@ -102,7 +102,7 @@ float_bench! { crate_fn_ppc: trunc::__trunckfsf2, sys_fn: __trunctfsf2, sys_fn_ppc: __trunckfsf2, - sys_available: not(feature = "no-sys-f128"), + sys_available: not(no_sys_f128), asm: [], } @@ -114,7 +114,7 @@ float_bench! { crate_fn_ppc: trunc::__trunckfdf2, sys_fn: __trunctfdf2, sys_fn_ppc: __trunckfdf2, - sys_available: not(feature = "no-sys-f128"), + sys_available: not(no_sys_f128), asm: [], } diff --git a/library/compiler-builtins/builtins-test/build.rs b/library/compiler-builtins/builtins-test/build.rs index 5b2dcd12ef86f..f70dcecfaee4d 100644 --- a/library/compiler-builtins/builtins-test/build.rs +++ b/library/compiler-builtins/builtins-test/build.rs @@ -6,7 +6,7 @@ mod builtins_configure { /// Features to enable #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] -enum Feature { +enum SetCfg { NoSysF128, NoSysF128IntConvert, NoSysF16, @@ -14,7 +14,15 @@ enum Feature { NoSysF16F128Convert, } -impl Feature { +impl SetCfg { + const ALL: &[Self] = &[ + Self::NoSysF128, + Self::NoSysF128IntConvert, + Self::NoSysF16, + Self::NoSysF16F64Convert, + Self::NoSysF16F128Convert, + ]; + fn implies(self) -> &'static [Self] { match self { Self::NoSysF128 => [Self::NoSysF128IntConvert, Self::NoSysF16F128Convert].as_slice(), @@ -24,13 +32,33 @@ impl Feature { Self::NoSysF16F128Convert => [].as_slice(), } } + + fn name(self) -> &'static str { + match self { + Self::NoSysF128 => "no_sys_f128", + Self::NoSysF128IntConvert => "no_sys_f128_int_convert", + Self::NoSysF16F64Convert => "no_sys_f16_f64_convert", + Self::NoSysF16F128Convert => "no_sys_f16_f128_convert", + Self::NoSysF16 => "no_sys_f16", + } + } + + fn warning(self) -> &'static str { + match self { + SetCfg::NoSysF128 => "using apfloat fallback for f128", + SetCfg::NoSysF128IntConvert => "using apfloat fallback for f128 <-> int conversions", + SetCfg::NoSysF16F64Convert => "using apfloat fallback for f16 <-> f64 conversions", + SetCfg::NoSysF16F128Convert => "using apfloat fallback for f16 <-> f128 conversions", + SetCfg::NoSysF16 => "using apfloat fallback for f16", + } + } } fn main() { println!("cargo::rerun-if-changed=../configure.rs"); let target = builtins_configure::Target::from_env(); - let mut features = HashSet::new(); + let mut to_set = HashSet::new(); // These platforms do not have f128 symbols available in their system libraries, so // skip related tests. @@ -51,14 +79,14 @@ fn main() { // . || target.arch == "powerpc64" { - features.insert(Feature::NoSysF128); + to_set.insert(SetCfg::NoSysF128); } if target.arch == "x86" { // 32-bit x86 does not have `__fixunstfti`/`__fixtfti` but does have everything else - features.insert(Feature::NoSysF128IntConvert); + to_set.insert(SetCfg::NoSysF128IntConvert); // FIXME: 32-bit x86 has a bug in `f128 -> f16` system libraries - features.insert(Feature::NoSysF16F128Convert); + to_set.insert(SetCfg::NoSysF16F128Convert); } // These platforms do not have f16 symbols available in their system libraries, so @@ -77,42 +105,30 @@ fn main() { || target.arch == "wasm32" || target.arch == "wasm64" { - features.insert(Feature::NoSysF16); + to_set.insert(SetCfg::NoSysF16); } // These platforms are missing either `__extendhfdf2` or `__truncdfhf2`. if target.vendor == "apple" || target.os == "windows" { - features.insert(Feature::NoSysF16F64Convert); + to_set.insert(SetCfg::NoSysF16F64Convert); } // Add implied features. Collection is required for borrows. - features.extend( - features + to_set.extend( + to_set .iter() .flat_map(|x| x.implies()) .copied() .collect::>(), ); - for feature in features { - let (name, warning) = match feature { - Feature::NoSysF128 => ("no-sys-f128", "using apfloat fallback for f128"), - Feature::NoSysF128IntConvert => ( - "no-sys-f128-int-convert", - "using apfloat fallback for f128 <-> int conversions", - ), - Feature::NoSysF16F64Convert => ( - "no-sys-f16-f64-convert", - "using apfloat fallback for f16 <-> f64 conversions", - ), - Feature::NoSysF16F128Convert => ( - "no-sys-f16-f128-convert", - "using apfloat fallback for f16 <-> f128 conversions", - ), - Feature::NoSysF16 => ("no-sys-f16", "using apfloat fallback for f16"), - }; - println!("cargo:warning={warning}"); - println!("cargo:rustc-cfg=feature=\"{name}\""); + for cfg in SetCfg::ALL { + println!("cargo:rustc-check-cfg=cfg({})", cfg.name()); + } + + for cfg in to_set { + println!("cargo:warning={}", cfg.warning()); + println!("cargo:rustc-cfg={}", cfg.name()); } builtins_configure::configure_aliases(&target); diff --git a/library/compiler-builtins/builtins-test/tests/addsub.rs b/library/compiler-builtins/builtins-test/tests/addsub.rs index de1235bce54fc..859de3e425538 100644 --- a/library/compiler-builtins/builtins-test/tests/addsub.rs +++ b/library/compiler-builtins/builtins-test/tests/addsub.rs @@ -131,12 +131,12 @@ mod float_addsub { #[cfg(not(x86_no_sse2))] #[cfg(not(any(target_arch = "powerpc", target_arch = "powerpc64")))] float_sum! { - f128, __addtf3, __subtf3, Quad, not(feature = "no-sys-f128"); + f128, __addtf3, __subtf3, Quad, not(no_sys_f128); } #[cfg(f128_enabled)] #[cfg(any(target_arch = "powerpc", target_arch = "powerpc64"))] float_sum! { - f128, __addkf3, __subkf3, Quad, not(feature = "no-sys-f128"); + f128, __addkf3, __subkf3, Quad, not(no_sys_f128); } } diff --git a/library/compiler-builtins/builtins-test/tests/cmp.rs b/library/compiler-builtins/builtins-test/tests/cmp.rs index 4b01b6ca1c7d7..d9360027a9643 100644 --- a/library/compiler-builtins/builtins-test/tests/cmp.rs +++ b/library/compiler-builtins/builtins-test/tests/cmp.rs @@ -125,19 +125,19 @@ mod float_comparisons { fuzz_float_2(N, |x: f128, y: f128| { let x_is_nan = apfloat_fallback!( - f128, Quad, not(feature = "no-sys-f128"), + f128, Quad, not(no_sys_f128), |x: FloatTy| x.is_nan() => no_convert, x ); let y_is_nan = apfloat_fallback!( - f128, Quad, not(feature = "no-sys-f128"), + f128, Quad, not(no_sys_f128), |x: FloatTy| x.is_nan() => no_convert, y ); assert_eq!(__unordtf2(x, y) != 0, x_is_nan || y_is_nan); - cmp!(f128, x, y, Quad, not(feature = "no-sys-f128"), + cmp!(f128, x, y, Quad, not(no_sys_f128), 1, __lttf2; 1, __letf2; 1, __eqtf2; diff --git a/library/compiler-builtins/builtins-test/tests/conv.rs b/library/compiler-builtins/builtins-test/tests/conv.rs index 9d8dde52bac38..e01eb259ac869 100644 --- a/library/compiler-builtins/builtins-test/tests/conv.rs +++ b/library/compiler-builtins/builtins-test/tests/conv.rs @@ -117,7 +117,7 @@ mod i_to_f { #[cfg(f128_enabled)] #[cfg(not(any(target_arch = "powerpc", target_arch = "powerpc64")))] - i_to_f! { f128, Quad, not(feature = "no-sys-f128-int-convert"), + i_to_f! { f128, Quad, not(no_sys_f128_int_convert), u32, __floatunsitf; i32, __floatsitf; u64, __floatunditf; @@ -128,7 +128,7 @@ mod i_to_f { #[cfg(f128_enabled)] #[cfg(any(target_arch = "powerpc", target_arch = "powerpc64"))] - i_to_f! { f128, Quad, not(feature = "no-sys-f128-int-convert"), + i_to_f! { f128, Quad, not(no_sys_f128_int_convert), u32, __floatunsikf; i32, __floatsikf; u64, __floatundikf; @@ -236,7 +236,7 @@ mod f_to_i { x, f128, Quad, - not(feature = "no-sys-f128-int-convert"), + not(no_sys_f128_int_convert), u32, __fixunstfsi; u64, __fixunstfdi; u128, __fixunstfti; @@ -309,12 +309,12 @@ mod extend { )))] f_to_f! { extend, - f16 => f32, Half => Single, __extendhfsf2, not(feature = "no-sys-f16"); - f16 => f32, Half => Single, __gnu_h2f_ieee, not(feature = "no-sys-f16"); - f16 => f64, Half => Double, __extendhfdf2, not(feature = "no-sys-f16-f64-convert"); - f16 => f128, Half => Quad, __extendhftf2, not(feature = "no-sys-f16-f128-convert"); - f32 => f128, Single => Quad, __extendsftf2, not(feature = "no-sys-f128"); - f64 => f128, Double => Quad, __extenddftf2, not(feature = "no-sys-f128"); + f16 => f32, Half => Single, __extendhfsf2, not(no_sys_f16); + f16 => f32, Half => Single, __gnu_h2f_ieee, not(no_sys_f16); + f16 => f64, Half => Double, __extendhfdf2, not(no_sys_f16_f64_convert); + f16 => f128, Half => Quad, __extendhftf2, not(no_sys_f16_f128_convert); + f32 => f128, Single => Quad, __extendsftf2, not(no_sys_f128); + f64 => f128, Double => Quad, __extenddftf2, not(no_sys_f128); } #[cfg(f128_enabled)] @@ -322,8 +322,8 @@ mod extend { f_to_f! { extend, // FIXME(#655): `f16` tests disabled until we can bootstrap symbols - f32 => f128, Single => Quad, __extendsfkf2, not(feature = "no-sys-f128"); - f64 => f128, Double => Quad, __extenddfkf2, not(feature = "no-sys-f128"); + f32 => f128, Single => Quad, __extendsfkf2, not(no_sys_f128); + f64 => f128, Double => Quad, __extenddfkf2, not(no_sys_f128); } } @@ -343,12 +343,12 @@ mod trunc { )))] f_to_f! { trunc, - f32 => f16, Single => Half, __truncsfhf2, not(feature = "no-sys-f16"); - f32 => f16, Single => Half, __gnu_f2h_ieee, not(feature = "no-sys-f16"); - f64 => f16, Double => Half, __truncdfhf2, not(feature = "no-sys-f16-f64-convert"); - f128 => f16, Quad => Half, __trunctfhf2, not(feature = "no-sys-f16-f128-convert"); - f128 => f32, Quad => Single, __trunctfsf2, not(feature = "no-sys-f128"); - f128 => f64, Quad => Double, __trunctfdf2, not(feature = "no-sys-f128"); + f32 => f16, Single => Half, __truncsfhf2, not(no_sys_f16); + f32 => f16, Single => Half, __gnu_f2h_ieee, not(no_sys_f16); + f64 => f16, Double => Half, __truncdfhf2, not(no_sys_f16_f64_convert); + f128 => f16, Quad => Half, __trunctfhf2, not(no_sys_f16_f128_convert); + f128 => f32, Quad => Single, __trunctfsf2, not(no_sys_f128); + f128 => f64, Quad => Double, __trunctfdf2, not(no_sys_f128); } #[cfg(f128_enabled)] @@ -356,7 +356,7 @@ mod trunc { f_to_f! { trunc, // FIXME(#655): `f16` tests disabled until we can bootstrap symbols - f128 => f32, Quad => Single, __trunckfsf2, not(feature = "no-sys-f128"); - f128 => f64, Quad => Double, __trunckfdf2, not(feature = "no-sys-f128"); + f128 => f32, Quad => Single, __trunckfsf2, not(no_sys_f128); + f128 => f64, Quad => Double, __trunckfdf2, not(no_sys_f128); } } diff --git a/library/compiler-builtins/builtins-test/tests/div_rem.rs b/library/compiler-builtins/builtins-test/tests/div_rem.rs index fccd421828cab..5d04fe9c0a9b1 100644 --- a/library/compiler-builtins/builtins-test/tests/div_rem.rs +++ b/library/compiler-builtins/builtins-test/tests/div_rem.rs @@ -154,12 +154,12 @@ mod float_div { f128, __divtf3, Quad, // FIXME(llvm): there is a bug in LLVM rt. // See . - not(any(feature = "no-sys-f128", all(target_arch = "aarch64", target_os = "linux"))); + not(any(no_sys_f128, all(target_arch = "aarch64", target_os = "linux"))); } #[cfg(f128_enabled)] #[cfg(any(target_arch = "powerpc", target_arch = "powerpc64"))] float! { - f128, __divkf3, Quad, not(feature = "no-sys-f128"); + f128, __divkf3, Quad, not(no_sys_f128); } } diff --git a/library/compiler-builtins/builtins-test/tests/float_pow.rs b/library/compiler-builtins/builtins-test/tests/float_pow.rs index 750869de3e5a9..c808b9efae65f 100644 --- a/library/compiler-builtins/builtins-test/tests/float_pow.rs +++ b/library/compiler-builtins/builtins-test/tests/float_pow.rs @@ -62,11 +62,11 @@ pow! { #[cfg(f128_enabled)] #[cfg(not(any(target_arch = "powerpc", target_arch = "powerpc64")))] pow! { - f128, 1e-36, __powitf2, not(feature = "no-sys-f128"); + f128, 1e-36, __powitf2, not(no_sys_f128); } #[cfg(f128_enabled)] #[cfg(any(target_arch = "powerpc", target_arch = "powerpc64"))] pow! { - f128, 1e-36, __powikf2, not(feature = "no-sys-f128"); + f128, 1e-36, __powikf2, not(no_sys_f128); } diff --git a/library/compiler-builtins/builtins-test/tests/mul.rs b/library/compiler-builtins/builtins-test/tests/mul.rs index 7c3bffe4b159a..b16d729be1dd5 100644 --- a/library/compiler-builtins/builtins-test/tests/mul.rs +++ b/library/compiler-builtins/builtins-test/tests/mul.rs @@ -142,7 +142,7 @@ mod float_mul_f128 { f128, __multf3, Quad, // FIXME(llvm): there is a bug in LLVM rt. // See . - not(any(feature = "no-sys-f128", all(target_arch = "aarch64", target_os = "linux"))); + not(any(no_sys_f128, all(target_arch = "aarch64", target_os = "linux"))); } } @@ -152,6 +152,6 @@ mod float_mul_f128_ppc { use super::*; float_mul! { - f128, __mulkf3, Quad, not(feature = "no-sys-f128"); + f128, __mulkf3, Quad, not(no_sys_f128); } } From 3975322675edb16d8da30b152de3382610a74dce Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Wed, 1 Apr 2026 03:26:33 -0400 Subject: [PATCH 076/183] build: Print build config if LIBM_BUILD_VERBOSE is set Make it easier to see what is being enabled without enabling Cargo's `-vv` output. --- .../.github/workflows/main.yaml | 1 + .../compiler-builtins/builtins-test/build.rs | 17 +--- library/compiler-builtins/ci/run-docker.sh | 1 + .../compiler-builtins/build.rs | 25 ++---- .../compiler-builtins/configure.rs | 65 ++++++++++----- library/compiler-builtins/libm/build.rs | 11 ++- library/compiler-builtins/libm/configure.rs | 79 +++++++++++-------- 7 files changed, 105 insertions(+), 94 deletions(-) diff --git a/library/compiler-builtins/.github/workflows/main.yaml b/library/compiler-builtins/.github/workflows/main.yaml index f90b758536b0d..587092500e5e5 100644 --- a/library/compiler-builtins/.github/workflows/main.yaml +++ b/library/compiler-builtins/.github/workflows/main.yaml @@ -11,6 +11,7 @@ concurrency: env: CARGO_TERM_COLOR: always + LIBM_BUILD_VERBOSE: true RUSTDOCFLAGS: -Dwarnings RUSTFLAGS: -Dwarnings RUST_BACKTRACE: full diff --git a/library/compiler-builtins/builtins-test/build.rs b/library/compiler-builtins/builtins-test/build.rs index f70dcecfaee4d..46179cc7ffcf9 100644 --- a/library/compiler-builtins/builtins-test/build.rs +++ b/library/compiler-builtins/builtins-test/build.rs @@ -42,16 +42,6 @@ impl SetCfg { Self::NoSysF16 => "no_sys_f16", } } - - fn warning(self) -> &'static str { - match self { - SetCfg::NoSysF128 => "using apfloat fallback for f128", - SetCfg::NoSysF128IntConvert => "using apfloat fallback for f128 <-> int conversions", - SetCfg::NoSysF16F64Convert => "using apfloat fallback for f16 <-> f64 conversions", - SetCfg::NoSysF16F128Convert => "using apfloat fallback for f16 <-> f128 conversions", - SetCfg::NoSysF16 => "using apfloat fallback for f16", - } - } } fn main() { @@ -123,12 +113,7 @@ fn main() { ); for cfg in SetCfg::ALL { - println!("cargo:rustc-check-cfg=cfg({})", cfg.name()); - } - - for cfg in to_set { - println!("cargo:warning={}", cfg.warning()); - println!("cargo:rustc-cfg={}", cfg.name()); + builtins_configure::set_cfg(cfg.name(), to_set.contains(cfg)); } builtins_configure::configure_aliases(&target); diff --git a/library/compiler-builtins/ci/run-docker.sh b/library/compiler-builtins/ci/run-docker.sh index e65ada271904f..619e1a02359c2 100755 --- a/library/compiler-builtins/ci/run-docker.sh +++ b/library/compiler-builtins/ci/run-docker.sh @@ -78,6 +78,7 @@ run() { -e CI \ -e CARGO_TARGET_DIR=/builtins-target \ -e CARGO_TERM_COLOR \ + -e LIBM_BUILD_VERBOSE \ -e MAY_SKIP_LIBM_CI \ -e RUSTFLAGS \ -e RUST_BACKTRACE \ diff --git a/library/compiler-builtins/compiler-builtins/build.rs b/library/compiler-builtins/compiler-builtins/build.rs index 7166634260504..e95feded21855 100644 --- a/library/compiler-builtins/compiler-builtins/build.rs +++ b/library/compiler-builtins/compiler-builtins/build.rs @@ -2,7 +2,7 @@ mod configure; use std::env; -use configure::{Target, configure_aliases}; +use configure::{Target, configure_aliases, set_cfg}; fn main() { println!("cargo::rerun-if-changed=build.rs"); @@ -76,35 +76,26 @@ fn main() { // Only emit the ARM Linux atomic emulation on pre-ARMv6 architectures. This // includes the old androideabi. It is deprecated but it is available as a // rustc target (arm-linux-androideabi). - if llvm_target[0] == "armv4t" + let kernel_user_helpers = llvm_target[0] == "armv4t" || llvm_target[0] == "armv5te" - || target.triple == "arm-linux-androideabi" - { - println!("cargo:rustc-cfg=kernel_user_helpers") - } + || target.triple == "arm-linux-androideabi"; + set_cfg("kernel_user_helpers", kernel_user_helpers); } /// Run configuration for `libm` since it is included directly. /// /// Much of this is copied from `libm/configure.rs`. fn configure_libm(target: &Target) { - println!("cargo:rustc-check-cfg=cfg(intrinsics_enabled)"); - println!("cargo:rustc-check-cfg=cfg(arch_enabled)"); - println!("cargo:rustc-check-cfg=cfg(optimizations_enabled)"); println!("cargo:rustc-check-cfg=cfg(feature, values(\"unstable-public-internals\"))"); // Always use intrinsics - println!("cargo:rustc-cfg=intrinsics_enabled"); + set_cfg("intrinsics_enabled", true); // The arch module may contain assembly. - if !cfg!(feature = "no-asm") { - println!("cargo:rustc-cfg=arch_enabled"); - } + set_cfg("arch_enabled", !cfg!(feature = "no-asm")); - println!("cargo:rustc-check-cfg=cfg(optimizations_enabled)"); - if !matches!(target.opt_level.as_str(), "0" | "1") { - println!("cargo:rustc-cfg=optimizations_enabled"); - } + let opt = !matches!(target.opt_level.as_str(), "0" | "1"); + set_cfg("optimizations_enabled", opt); println!( "cargo:rustc-env=CFG_CARGO_FEATURES={:?}", diff --git a/library/compiler-builtins/compiler-builtins/configure.rs b/library/compiler-builtins/compiler-builtins/configure.rs index 874397aa48486..4dcb933834421 100644 --- a/library/compiler-builtins/compiler-builtins/configure.rs +++ b/library/compiler-builtins/compiler-builtins/configure.rs @@ -1,6 +1,12 @@ // Configuration that is shared between `compiler_builtins` and `builtins_test`. -use std::{env, str}; +use std::env::{self, VarError}; +use std::str; +use std::sync::atomic::AtomicBool; +use std::sync::atomic::Ordering::Relaxed; + +/// Read from env, print more debug output via `cargo:warning` if set. +static VERBOSE_BUILD: AtomicBool = AtomicBool::new(false); #[derive(Debug)] #[allow(dead_code)] @@ -22,6 +28,11 @@ pub struct Target { impl Target { pub fn from_env() -> Self { + println!("cargo:cargo::rerun-if-env-changed=LIBM_BUILD_VERBOSE"); + if env_flag("LIBM_BUILD_VERBOSE") { + VERBOSE_BUILD.store(true, Relaxed); + } + let triple = env::var("TARGET").unwrap(); let triple_split = triple.split('-').map(ToOwned::to_owned).collect(); let little_endian = match env::var("CARGO_CFG_TARGET_ENDIAN").unwrap().as_str() { @@ -33,6 +44,11 @@ impl Target { .filter_map(|(name, _value)| name.strip_prefix("CARGO_FEATURE_").map(ToOwned::to_owned)) .map(|s| s.to_lowercase().replace("_", "-")) .collect(); + if VERBOSE_BUILD.load(Relaxed) { + for feature in &cargo_features { + println!("cargo:warning=feature `{feature}` enabled"); + } + } Self { triple, @@ -68,25 +84,18 @@ impl Target { pub fn configure_aliases(target: &Target) { // To compile builtins-test-intrinsics for thumb targets, where there is no libc - println!("cargo::rustc-check-cfg=cfg(thumb)"); - if target.triple_split[0].starts_with("thumb") { - println!("cargo:rustc-cfg=thumb") - } + let thumb = target.triple_split[0].starts_with("thumb"); + set_cfg("thumb", thumb); // compiler-rt `cfg`s away some intrinsics for thumbv6m and thumbv8m.base because // these targets do not have full Thumb-2 support but only original Thumb-1. // We have to cfg our code accordingly. - println!("cargo::rustc-check-cfg=cfg(thumb_1)"); - if target.triple_split[0] == "thumbv6m" || target.triple_split[0] == "thumbv8m.base" { - println!("cargo:rustc-cfg=thumb_1") - } + let thumb_1 = target.triple_split[0] == "thumbv6m" || target.triple_split[0] == "thumbv8m.base"; + set_cfg("thumb_1", thumb_1); - // Config shorthands - println!("cargo:rustc-check-cfg=cfg(x86_no_sse2)"); - if target.arch == "x86" && !target.features.iter().any(|f| f == "sse2") { - // Shorthand to detect i586 targets - println!("cargo:rustc-cfg=x86_no_sse2"); - } + // Shorthand to detect i586 targets + let x86_no_sse2 = target.arch == "x86" && !target.features.iter().any(|f| f == "sse2"); + set_cfg("x86_no_sse2", x86_no_sse2); /* Not all backends support `f16` and `f128` to the same level on all architectures, so we * need to disable things if the compiler may crash. See configuration at: @@ -95,13 +104,27 @@ pub fn configure_aliases(target: &Target) { * * https://github.com/rust-lang/rustc_codegen_cranelift/blob/c713ffab3c6e28ab4b4dd4e392330f786ea657ad/src/lib.rs#L196-L226 */ - println!("cargo::rustc-check-cfg=cfg(f16_enabled)"); - if target.reliable_f16 { - println!("cargo::rustc-cfg=f16_enabled"); + set_cfg("f16_enabled", target.reliable_f16); + set_cfg("f128_enabled", target.reliable_f128); +} + +pub fn set_cfg(name: &str, set: bool) { + println!("cargo:rustc-check-cfg=cfg({name})"); + if !set { + return; } + if VERBOSE_BUILD.load(Relaxed) { + println!("cargo:warning=setting config `{name}`"); + } + println!("cargo:rustc-cfg={name}"); +} - println!("cargo::rustc-check-cfg=cfg(f128_enabled)"); - if target.reliable_f128 { - println!("cargo::rustc-cfg=f128_enabled"); +/// Return true if the env is set to a value other than `0`. +pub fn env_flag(key: &str) -> bool { + match env::var(key) { + Ok(x) if x == "0" => false, + Err(VarError::NotPresent) => false, + Err(VarError::NotUnicode(_)) => panic!("non-unicode var for `{key}`"), + Ok(_) => true, } } diff --git a/library/compiler-builtins/libm/build.rs b/library/compiler-builtins/libm/build.rs index 07d08ed4364db..054fa4b74ef76 100644 --- a/library/compiler-builtins/libm/build.rs +++ b/library/compiler-builtins/libm/build.rs @@ -1,7 +1,7 @@ -use std::env; - mod configure; +use configure::{emit_libm_config, env_flag, set_cfg}; + fn main() { let cfg = configure::Config::from_env(); @@ -10,9 +10,8 @@ fn main() { println!("cargo:rustc-check-cfg=cfg(assert_no_panic)"); // If set, enable `no-panic`. Requires LTO (`release-opt` profile). - if env::var("ENSURE_NO_PANIC").is_ok() { - println!("cargo:rustc-cfg=assert_no_panic"); - } + let no_panic = env_flag("ENSURE_NO_PANIC"); + set_cfg("assert_no_panic", no_panic); - configure::emit_libm_config(&cfg); + emit_libm_config(&cfg); } diff --git a/library/compiler-builtins/libm/configure.rs b/library/compiler-builtins/libm/configure.rs index eeace880b7e87..d42faa9794925 100644 --- a/library/compiler-builtins/libm/configure.rs +++ b/library/compiler-builtins/libm/configure.rs @@ -1,7 +1,12 @@ // Configuration shared with both libm and libm-test -use std::env; +use std::env::{self, VarError}; use std::path::PathBuf; +use std::sync::atomic::AtomicBool; +use std::sync::atomic::Ordering::Relaxed; + +/// Read from env, print more debug output via `cargo:warning` if set. +static VERBOSE_BUILD: AtomicBool = AtomicBool::new(false); #[derive(Debug)] #[allow(dead_code)] @@ -24,6 +29,11 @@ pub struct Config { impl Config { pub fn from_env() -> Self { + println!("cargo:cargo::rerun-if-env-changed=LIBM_BUILD_VERBOSE"); + if env_flag("LIBM_BUILD_VERBOSE") { + VERBOSE_BUILD.store(true, Relaxed); + } + let target_triple = env::var("TARGET").unwrap(); let target_families = env::var("CARGO_CFG_TARGET_FAMILY") .map(|feats| feats.split(',').map(ToOwned::to_owned).collect()) @@ -35,6 +45,11 @@ impl Config { .filter_map(|(name, _value)| name.strip_prefix("CARGO_FEATURE_").map(ToOwned::to_owned)) .map(|s| s.to_lowercase().replace("_", "-")) .collect(); + if VERBOSE_BUILD.load(Relaxed) { + for feature in &cargo_features { + println!("cargo:warning=feature `{feature}` enabled"); + } + } Self { target_triple, @@ -80,42 +95,31 @@ pub fn emit_test_config(cfg: &Config) { /// Simplify the feature logic for enabling intrinsics so code only needs to use /// `cfg(intrinsics_enabled)`. fn emit_intrinsics_cfg() { - println!("cargo:rustc-check-cfg=cfg(intrinsics_enabled)"); - // Disabled by default; `unstable-intrinsics` enables again; `force-soft-floats` overrides // to disable. - if cfg!(feature = "unstable-intrinsics") && !cfg!(feature = "force-soft-floats") { - println!("cargo:rustc-cfg=intrinsics_enabled"); - } + let intrinsics = cfg!(feature = "unstable-intrinsics") && !cfg!(feature = "force-soft-floats"); + set_cfg("intrinsics_enabled", intrinsics); } /// Simplify the feature logic for enabling arch-specific features so code only needs to use /// `cfg(arch_enabled)`. fn emit_arch_cfg() { - println!("cargo:rustc-check-cfg=cfg(arch_enabled)"); - // Enabled by default via the "arch" feature, `force-soft-floats` overrides to disable. - if cfg!(feature = "arch") && !cfg!(feature = "force-soft-floats") { - println!("cargo:rustc-cfg=arch_enabled"); - } + let arch = cfg!(feature = "arch") && !cfg!(feature = "force-soft-floats"); + set_cfg("arch_enabled", arch); } /// Some tests are extremely slow. Emit a config option based on optimization level. fn emit_optimization_cfg(cfg: &Config) { - println!("cargo:rustc-check-cfg=cfg(optimizations_enabled)"); - - if !matches!(cfg.opt_level.as_str(), "0" | "1") { - println!("cargo:rustc-cfg=optimizations_enabled"); - } + let opt = !matches!(cfg.opt_level.as_str(), "0" | "1"); + set_cfg("optimizations_enabled", opt); } /// Provide an alias for common longer config combinations. fn emit_cfg_shorthands(cfg: &Config) { - println!("cargo:rustc-check-cfg=cfg(x86_no_sse2)"); - if cfg.target_arch == "x86" && !cfg.target_features.iter().any(|f| f == "sse2") { - // Shorthand to detect i586 targets - println!("cargo:rustc-cfg=x86_no_sse2"); - } + // Shorthand to detect i586 targets + let x86_no_sse2 = cfg.target_arch == "x86" && !cfg.target_features.iter().any(|f| f == "sse2"); + set_cfg("x86_no_sse2", x86_no_sse2); } /// Reemit config that we make use of for test logging. @@ -133,23 +137,30 @@ fn emit_cfg_env(cfg: &Config) { /// Configure whether or not `f16` and `f128` support should be enabled. fn emit_f16_f128_cfg(cfg: &Config) { - println!("cargo:rustc-check-cfg=cfg(f16_enabled)"); - println!("cargo:rustc-check-cfg=cfg(f128_enabled)"); + // `unstable-float` enables these features. See the compiler-builtins file for their + // meaning. + let unstable_float = cfg!(feature = "unstable-float"); + set_cfg("f16_enabled", unstable_float && cfg.reliable_f16); + set_cfg("f128_enabled", unstable_float && cfg.reliable_f128); +} - // `unstable-float` enables these features. - if !cfg!(feature = "unstable-float") { +pub fn set_cfg(name: &str, set: bool) { + println!("cargo:rustc-check-cfg=cfg({name})"); + if !set { return; } - - /* See the compiler-builtins configure file for info about the meaning of these options */ - - println!("cargo:rustc-check-cfg=cfg(f16_enabled)"); - if cfg.reliable_f16 { - println!("cargo:rustc-cfg=f16_enabled"); + if VERBOSE_BUILD.load(Relaxed) { + println!("cargo:warning=setting config `{name}`"); } + println!("cargo:rustc-cfg={name}"); +} - println!("cargo:rustc-check-cfg=cfg(f128_enabled)"); - if cfg.reliable_f128 { - println!("cargo:rustc-cfg=f128_enabled"); +/// Return true if the env is set to a value other than `0`. +pub fn env_flag(key: &str) -> bool { + match env::var(key) { + Ok(x) if x == "0" => false, + Err(VarError::NotPresent) => false, + Err(VarError::NotUnicode(_)) => panic!("non-unicode var for `{key}`"), + Ok(_) => true, } } From b551fa8f033205680c03c0f8c6a463d6556de570 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Wed, 1 Apr 2026 03:36:38 -0400 Subject: [PATCH 077/183] c-b: Turn `mem-unaligned` from a feature to a cfg For anything that doesn't need to be configurable via Cargo, using a `cfg` rather than a feature is cleaner. --- .../compiler-builtins/compiler-builtins/build.rs | 8 +++----- .../compiler-builtins/src/mem/impls.rs | 16 ++++++++-------- 2 files changed, 11 insertions(+), 13 deletions(-) diff --git a/library/compiler-builtins/compiler-builtins/build.rs b/library/compiler-builtins/compiler-builtins/build.rs index e95feded21855..3b1ad344e2a30 100644 --- a/library/compiler-builtins/compiler-builtins/build.rs +++ b/library/compiler-builtins/compiler-builtins/build.rs @@ -46,13 +46,11 @@ fn main() { } // These targets have hardware unaligned access support. - if target.arch.contains("x86_64") + let mem_unaligned = target.arch.contains("x86_64") || target.arch.contains("x86") || target.arch.contains("aarch64") - || target.arch.contains("bpf") - { - println!("cargo:rustc-cfg=feature=\"mem-unaligned\""); - } + || target.arch.contains("bpf"); + set_cfg("mem_unaligned", mem_unaligned); // NOTE we are going to assume that llvm-target, what determines our codegen option, matches the // target triple. This is usually correct for our built-in targets but can break in presence of diff --git a/library/compiler-builtins/compiler-builtins/src/mem/impls.rs b/library/compiler-builtins/compiler-builtins/src/mem/impls.rs index 9681f5d6dac6e..a6486381bf75c 100644 --- a/library/compiler-builtins/compiler-builtins/src/mem/impls.rs +++ b/library/compiler-builtins/compiler-builtins/src/mem/impls.rs @@ -35,7 +35,7 @@ const WORD_COPY_THRESHOLD: usize = if 2 * WORD_SIZE > 16 { 16 }; -#[cfg(feature = "mem-unaligned")] +#[cfg(mem_unaligned)] unsafe fn read_usize_unaligned(x: *const usize) -> usize { // Do not use `core::ptr::read_unaligned` here, since it calls `copy_nonoverlapping` which // is translated to memcpy in LLVM. @@ -46,7 +46,7 @@ unsafe fn read_usize_unaligned(x: *const usize) -> usize { /// Loads a `T`-sized chunk from `src` into `dst` at offset `offset`, if that does not exceed /// `load_sz`. The offset pointers must both be `T`-aligned. Returns the new offset, advanced by the /// chunk size if a load happened. -#[cfg(not(feature = "mem-unaligned"))] +#[cfg(not(mem_unaligned))] #[inline(always)] unsafe fn load_chunk_aligned( src: *const usize, @@ -66,7 +66,7 @@ unsafe fn load_chunk_aligned( /// Load `load_sz` many bytes from `src`, which must be usize-aligned. Acts as if we did a `usize` /// read with the out-of-bounds part filled with 0s. /// `load_sz` be strictly less than `WORD_SIZE`. -#[cfg(not(feature = "mem-unaligned"))] +#[cfg(not(mem_unaligned))] #[inline(always)] unsafe fn load_aligned_partial(src: *const usize, load_sz: usize) -> usize { debug_assert!(load_sz < WORD_SIZE); @@ -88,7 +88,7 @@ unsafe fn load_aligned_partial(src: *const usize, load_sz: usize) -> usize { /// `usize`-aligned. The bytes are returned as the *last* bytes of the return value, i.e., this acts /// as if we had done a `usize` read from `src`, with the out-of-bounds part filled with 0s. /// `load_sz` be strictly less than `WORD_SIZE`. -#[cfg(not(feature = "mem-unaligned"))] +#[cfg(not(mem_unaligned))] #[inline(always)] unsafe fn load_aligned_end_partial(src: *const usize, load_sz: usize) -> usize { debug_assert!(load_sz < WORD_SIZE); @@ -136,7 +136,7 @@ pub unsafe fn copy_forward(mut dest: *mut u8, mut src: *const u8, mut n: usize) /// `n` is in units of bytes, but must be a multiple of the word size and must not be 0. /// `src` *must not* be `usize`-aligned. - #[cfg(not(feature = "mem-unaligned"))] + #[cfg(not(mem_unaligned))] #[inline(always)] unsafe fn copy_forward_misaligned_words(dest: *mut u8, src: *const u8, n: usize) { debug_assert!(n > 0 && n % WORD_SIZE == 0); @@ -185,7 +185,7 @@ pub unsafe fn copy_forward(mut dest: *mut u8, mut src: *const u8, mut n: usize) /// `n` is in units of bytes, but must be a multiple of the word size and must not be 0. /// `src` *must not* be `usize`-aligned. - #[cfg(feature = "mem-unaligned")] + #[cfg(mem_unaligned)] #[inline(always)] unsafe fn copy_forward_misaligned_words(dest: *mut u8, src: *const u8, n: usize) { let mut dest_usize = dest as *mut usize; @@ -252,7 +252,7 @@ pub unsafe fn copy_backward(dest: *mut u8, src: *const u8, mut n: usize) { /// `n` is in units of bytes, but must be a multiple of the word size and must not be 0. /// `src` *must not* be `usize`-aligned. - #[cfg(not(feature = "mem-unaligned"))] + #[cfg(not(mem_unaligned))] #[inline(always)] unsafe fn copy_backward_misaligned_words(dest: *mut u8, src: *const u8, n: usize) { debug_assert!(n > 0 && n % WORD_SIZE == 0); @@ -301,7 +301,7 @@ pub unsafe fn copy_backward(dest: *mut u8, src: *const u8, mut n: usize) { /// `n` is in units of bytes, but must be a multiple of the word size and must not be 0. /// `src` *must not* be `usize`-aligned. - #[cfg(feature = "mem-unaligned")] + #[cfg(mem_unaligned)] #[inline(always)] unsafe fn copy_backward_misaligned_words(dest: *mut u8, src: *const u8, n: usize) { let mut dest_usize = dest as *mut usize; From c1c86519dcb600ee815e565279f8f608baa6c0d8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Ber=C3=A1nek?= Date: Wed, 1 Apr 2026 11:21:19 +0200 Subject: [PATCH 078/183] ci: Fix rustc-pull workflow See https://github.com/rust-lang/josh-sync/pull/40. --- library/compiler-builtins/.github/workflows/rustc-pull.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/library/compiler-builtins/.github/workflows/rustc-pull.yml b/library/compiler-builtins/.github/workflows/rustc-pull.yml index 7d193eef0a50d..ff8305d3729fd 100644 --- a/library/compiler-builtins/.github/workflows/rustc-pull.yml +++ b/library/compiler-builtins/.github/workflows/rustc-pull.yml @@ -13,9 +13,10 @@ env: jobs: pull: if: github.repository == 'rust-lang/compiler-builtins' - uses: rust-lang/josh-sync/.github/workflows/rustc-pull.yml@a097aeb82f49801051560482307ceaca7e58bf97 # main + uses: rust-lang/josh-sync/.github/workflows/rustc-pull.yml@8970a6eb3a6095db68e4d765b3b5fba5e9c42cf6 # main with: github-app-id: ${{ vars.APP_CLIENT_ID }} + pr-author: "workflows-compiler-builtins[bot]" # https://rust-lang.zulipchat.com/#narrow/channel/219381-t-libs/topic/compiler-builtins.20subtree.20sync.20automation/with/528482375 zulip-stream-id: 219381 zulip-topic: "compiler-builtins subtree sync automation" From 7d709d16ad7c50225033fc17f6c38ae9a5ad5607 Mon Sep 17 00:00:00 2001 From: Marco Ieni <11428655+marcoieni@users.noreply.github.com> Date: Wed, 1 Apr 2026 11:31:28 +0200 Subject: [PATCH 079/183] renovate: don't raise individual PRs for crates non breaking changes Before this PR, we were receiving PRs when crate `1.2.3` was updated to `1.3.0`. With this PR, we should receive PRs only when `2.0.0` is out. Similar to https://github.com/rust-lang/crates-io-auth-action/pull/220 --- library/compiler-builtins/.github/renovate.json5 | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/library/compiler-builtins/.github/renovate.json5 b/library/compiler-builtins/.github/renovate.json5 index 6a269ab449861..7d18fd573d6d8 100644 --- a/library/compiler-builtins/.github/renovate.json5 +++ b/library/compiler-builtins/.github/renovate.json5 @@ -10,10 +10,10 @@ matchCategories: [ "rust" ], - matchUpdateTypes: [ - "patch" + matchJsonata: [ + "isBreaking != true" ], - // Disable patch updates for single dependencies because patches + // Disable non-breaking change updates because they // are updated periodically with lockfile maintainance. enabled: false, }, From 6dd2ec0ce553fe4425ffc6a6cf99404219469fe8 Mon Sep 17 00:00:00 2001 From: Mend Renovate Date: Wed, 1 Apr 2026 09:44:14 +0000 Subject: [PATCH 080/183] chore(deps): update rust crate object to 0.39.0 --- library/compiler-builtins/Cargo.lock | 20 ++++++++++---------- library/compiler-builtins/Cargo.toml | 2 +- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/library/compiler-builtins/Cargo.lock b/library/compiler-builtins/Cargo.lock index 372e7e68f5fbf..fc99f816d59ec 100644 --- a/library/compiler-builtins/Cargo.lock +++ b/library/compiler-builtins/Cargo.lock @@ -754,14 +754,14 @@ dependencies = [ [[package]] name = "object" -version = "0.38.1" +version = "0.39.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "271638cd5fa9cca89c4c304675ca658efc4e64a66c716b7cfe1afb4b9611dbbc" +checksum = "63944c133d03f44e75866bbd160b95af0ec3f6a13d936d69d31c81078cbc5baf" dependencies = [ "flate2", "memchr", "ruzstd", - "wasmparser 0.243.0", + "wasmparser 0.245.1", ] [[package]] @@ -1361,23 +1361,23 @@ dependencies = [ [[package]] name = "wasmparser" -version = "0.243.0" +version = "0.244.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f6d8db401b0528ec316dfbe579e6ab4152d61739cfe076706d2009127970159d" +checksum = "47b807c72e1bac69382b3a6fb3dbe8ea4c0ed87ff5629b8685ae6b9a611028fe" dependencies = [ "bitflags", + "hashbrown 0.15.5", + "indexmap", + "semver", ] [[package]] name = "wasmparser" -version = "0.244.0" +version = "0.245.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "47b807c72e1bac69382b3a6fb3dbe8ea4c0ed87ff5629b8685ae6b9a611028fe" +checksum = "4f08c9adee0428b7bddf3890fc27e015ac4b761cc608c822667102b8bfd6995e" dependencies = [ "bitflags", - "hashbrown 0.15.5", - "indexmap", - "semver", ] [[package]] diff --git a/library/compiler-builtins/Cargo.toml b/library/compiler-builtins/Cargo.toml index 478889ab4a633..8f65394c782c7 100644 --- a/library/compiler-builtins/Cargo.toml +++ b/library/compiler-builtins/Cargo.toml @@ -53,7 +53,7 @@ libm-test = { path = "libm-test", default-features = false } libtest-mimic = "0.8.1" musl-math-sys = { path = "crates/musl-math-sys" } no-panic = "0.1.36" -object = { version = "0.38.1", features = ["wasm"] } +object = { version = "0.39.0", features = ["wasm"] } panic-handler = { path = "crates/panic-handler" } paste = "1.0.15" proc-macro2 = "1.0.106" From 9c41dadd305fc5704b9410699fe9bad971c9d4fb Mon Sep 17 00:00:00 2001 From: Mend Renovate Date: Wed, 1 Apr 2026 09:59:33 +0000 Subject: [PATCH 081/183] chore(deps): update actions/upload-artifact action to v7 --- library/compiler-builtins/.github/workflows/main.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/.github/workflows/main.yaml b/library/compiler-builtins/.github/workflows/main.yaml index 587092500e5e5..ee83c0d611ea2 100644 --- a/library/compiler-builtins/.github/workflows/main.yaml +++ b/library/compiler-builtins/.github/workflows/main.yaml @@ -316,7 +316,7 @@ jobs: run: ./ci/bench-icount.sh "$JOB_TARGET" - name: Upload the benchmark baseline - uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6 + uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 with: name: ${{ env.BASELINE_NAME }} path: ${{ env.BASELINE_NAME }}.tar.xz From d89fb1df02166f459eb26d11cd1b9b63b0780373 Mon Sep 17 00:00:00 2001 From: Mend Renovate Date: Wed, 1 Apr 2026 09:59:16 +0000 Subject: [PATCH 082/183] chore(deps): update github actions --- .../.github/workflows/main.yaml | 44 +++++++++---------- .../.github/workflows/publish.yaml | 2 +- 2 files changed, 23 insertions(+), 23 deletions(-) diff --git a/library/compiler-builtins/.github/workflows/main.yaml b/library/compiler-builtins/.github/workflows/main.yaml index ee83c0d611ea2..83eac57fd9452 100644 --- a/library/compiler-builtins/.github/workflows/main.yaml +++ b/library/compiler-builtins/.github/workflows/main.yaml @@ -30,7 +30,7 @@ jobs: extensive_matrix: ${{ steps.script.outputs.extensive_matrix }} may_skip_libm_ci: ${{ steps.script.outputs.may_skip_libm_ci }} steps: - - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 with: persist-credentials: false fetch-depth: 500 @@ -132,7 +132,7 @@ jobs: if: matrix.os == 'ubuntu-24.04-ppc64le' || matrix.os == 'ubuntu-24.04-s390x' run: sudo apt-get update && sudo apt-get install -y rustup - - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 with: { persist-credentials: false } - name: Install Rust (rustup) shell: bash @@ -144,15 +144,15 @@ jobs: rustup default "$channel" rustup target add "$JOB_TARGET" - - uses: taiki-e/install-action@42721ded7ddc3cd90f687527e8602066e4e1ff3a # v2.69.2 + - uses: taiki-e/install-action@bfadeaba214680fb4ab63e710bcb2a6a17019fdc # v2.70.4 with: tool: nextest@0.9.131 - - uses: Swatinem/rust-cache@e18b497796c12c097a38f9edb9d0641fb99eee32 # v2 + - uses: Swatinem/rust-cache@c19371144df3bb44fab255c43d04cbc2ab54d1c4 # v2.9.1 with: key: ${{ matrix.target }} - name: Cache Docker layers - uses: actions/cache@cdf6c1fa76f9f475f3d7449005a359c84ca0f306 # v5 + uses: actions/cache@668228422ae6a00e4ad889ee87cd7109ec5666a7 # v5.0.4 if: ${{ env.RUN_IN_DOCKER == 'true' }} with: path: /tmp/.buildx-cache @@ -164,7 +164,7 @@ jobs: - name: Cache compiler-rt id: cache-compiler-rt - uses: actions/cache@cdf6c1fa76f9f475f3d7449005a359c84ca0f306 # v5 + uses: actions/cache@668228422ae6a00e4ad889ee87cd7109ec5666a7 # v5.0.4 with: path: compiler-rt key: ${{ runner.os }}-compiler-rt-${{ hashFiles('ci/download-compiler-rt.sh') }} @@ -213,7 +213,7 @@ jobs: runs-on: ubuntu-24.04 timeout-minutes: 10 steps: - - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 with: { persist-credentials: false } # Unlike rustfmt, stable clippy does not work on code with nightly features. - name: Install nightly `clippy` @@ -221,7 +221,7 @@ jobs: rustup update nightly --no-self-update rustup default nightly rustup component add clippy - - uses: Swatinem/rust-cache@e18b497796c12c097a38f9edb9d0641fb99eee32 # v2 + - uses: Swatinem/rust-cache@c19371144df3bb44fab255c43d04cbc2ab54d1c4 # v2.9.1 - name: Download musl source run: ./ci/update-musl.sh - run: cargo clippy --workspace --all-targets @@ -242,14 +242,14 @@ jobs: runs-on: ubuntu-24.04 timeout-minutes: 10 steps: - - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 with: { persist-credentials: false } - name: Install Rust run: | rustup update nightly --no-self-update rustup default nightly rustup component add rust-src - - uses: Swatinem/rust-cache@e18b497796c12c097a38f9edb9d0641fb99eee32 # v2 + - uses: Swatinem/rust-cache@c19371144df3bb44fab255c43d04cbc2ab54d1c4 # v2.9.1 - run: | # Ensure we can build with custom target.json files (these can interact # poorly with build scripts) @@ -264,14 +264,14 @@ jobs: runs-on: ubuntu-24.04 timeout-minutes: 10 steps: - - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 with: { persist-credentials: false } - name: Install Rust run: | rustup update nightly --no-self-update rustup default nightly rustup component add rust-src - - uses: Swatinem/rust-cache@e18b497796c12c097a38f9edb9d0641fb99eee32 # v2 + - uses: Swatinem/rust-cache@c19371144df3bb44fab255c43d04cbc2ab54d1c4 # v2.9.1 - run: | cargo build -p compiler_builtins -p libm \ --target etc/thumbv6-none-eabi.json \ @@ -295,15 +295,15 @@ jobs: env: JOB_TARGET: ${{ matrix.target }} steps: - - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 with: { persist-credentials: false } - - uses: taiki-e/install-action@de6bbd1333b8f331563d54a051e542c7dfef81c3 # v2.68.34 + - uses: taiki-e/install-action@bfadeaba214680fb4ab63e710bcb2a6a17019fdc # v2.70.4 with: tool: cargo-binstall@1.17.7 - name: Set up dependencies run: ./ci/install-bench-deps.sh "$JOB_TARGET" - - uses: Swatinem/rust-cache@e18b497796c12c097a38f9edb9d0641fb99eee32 # v2 + - uses: Swatinem/rust-cache@c19371144df3bb44fab255c43d04cbc2ab54d1c4 # v2.9.1 with: key: ${{ matrix.target }} - name: Download musl source @@ -331,14 +331,14 @@ jobs: runs-on: ubuntu-24.04 timeout-minutes: 10 steps: - - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 with: { persist-credentials: false } - name: Install Rust (rustup) run: rustup update nightly --no-self-update && rustup default nightly shell: bash - run: rustup component add miri - run: cargo miri setup - - uses: Swatinem/rust-cache@e18b497796c12c097a38f9edb9d0641fb99eee32 # v2 + - uses: Swatinem/rust-cache@c19371144df3bb44fab255c43d04cbc2ab54d1c4 # v2.9.1 - run: ./ci/miri.sh msrv: @@ -348,14 +348,14 @@ jobs: env: RUSTFLAGS: # No need to check warnings on old MSRV, unset `-Dwarnings` steps: - - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 with: { persist-credentials: false } - name: Install Rust run: | msrv="$(perl -ne 'print if s/rust-version\s*=\s*"(.*)"/\1/g' libm/Cargo.toml)" echo "MSRV: $msrv" rustup update "$msrv" --no-self-update && rustup default "$msrv" - - uses: Swatinem/rust-cache@e18b497796c12c097a38f9edb9d0641fb99eee32 # v2 + - uses: Swatinem/rust-cache@c19371144df3bb44fab255c43d04cbc2ab54d1c4 # v2.9.1 - run: | # FIXME(msrv): Remove the workspace Cargo.toml so 1.63 cargo doesn't see # `edition = "2024"` and get spooked. @@ -367,7 +367,7 @@ jobs: runs-on: ubuntu-24.04 timeout-minutes: 10 steps: - - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 with: { persist-credentials: false } - name: Install nightly `rustfmt` run: rustup set profile minimal && rustup default nightly && rustup component add rustfmt @@ -391,13 +391,13 @@ jobs: env: TO_TEST: ${{ matrix.to_test }} steps: - - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 with: { persist-credentials: false } - name: Install Rust run: | rustup update nightly --no-self-update rustup default nightly - - uses: Swatinem/rust-cache@e18b497796c12c097a38f9edb9d0641fb99eee32 # v2 + - uses: Swatinem/rust-cache@c19371144df3bb44fab255c43d04cbc2ab54d1c4 # v2.9.1 - name: download musl source run: ./ci/update-musl.sh - name: Run extensive tests diff --git a/library/compiler-builtins/.github/workflows/publish.yaml b/library/compiler-builtins/.github/workflows/publish.yaml index 738de77305ec8..aa742914a5344 100644 --- a/library/compiler-builtins/.github/workflows/publish.yaml +++ b/library/compiler-builtins/.github/workflows/publish.yaml @@ -13,7 +13,7 @@ jobs: runs-on: ubuntu-24.04 environment: publish steps: - - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 with: persist-credentials: false fetch-depth: 0 From 858156eb429b2bb278dc5780d07ad252849efcda Mon Sep 17 00:00:00 2001 From: Mend Renovate Date: Wed, 1 Apr 2026 10:00:46 +0000 Subject: [PATCH 083/183] chore(deps): lock file maintenance --- library/compiler-builtins/Cargo.lock | 235 +++++++++------------------ 1 file changed, 80 insertions(+), 155 deletions(-) diff --git a/library/compiler-builtins/Cargo.lock b/library/compiler-builtins/Cargo.lock index fc99f816d59ec..fbfb62ede17a2 100644 --- a/library/compiler-builtins/Cargo.lock +++ b/library/compiler-builtins/Cargo.lock @@ -34,9 +34,9 @@ checksum = "4b46cbb362ab8752921c97e041f5e366ee6297bd428a31275b9fcf1e380f7299" [[package]] name = "anstream" -version = "0.6.21" +version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "43d5b281e737544384e969a5ccad3f1cdd24b48086a0fc1b2a5262a26b8f4f4a" +checksum = "824a212faf96e9acacdbd09febd34438f8f711fb84e09a8916013cd7815ca28d" dependencies = [ "anstyle", "anstyle-parse", @@ -49,15 +49,15 @@ dependencies = [ [[package]] name = "anstyle" -version = "1.0.13" +version = "1.0.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5192cca8006f1fd4f7237516f40fa183bb07f8fbdfedaa0036de5ea9b0b45e78" +checksum = "940b3a0ca603d1eade50a4846a2afffd5ef57a9feac2c0e2ec2e14f9ead76000" [[package]] name = "anstyle-parse" -version = "0.2.7" +version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4e7644824f0aa2c7b9384579234ef10eb7efb6a0deb83f9630a49594dd9c15c2" +checksum = "52ce7f38b242319f7cabaa6813055467063ecdc9d355bbb4ce0c68908cd8130e" dependencies = [ "utf8parse", ] @@ -68,7 +68,7 @@ version = "1.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "40c48f72fd53cd289104fc64099abca73db4166ad86ea0b4341abe65af83dadc" dependencies = [ - "windows-sys 0.61.2", + "windows-sys", ] [[package]] @@ -79,14 +79,14 @@ checksum = "291e6a250ff86cd4a820112fb8898808a366d8f9f58ce16d1f538353ad55747d" dependencies = [ "anstyle", "once_cell_polyfill", - "windows-sys 0.61.2", + "windows-sys", ] [[package]] name = "anyhow" -version = "1.0.101" +version = "1.0.102" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f0e0fee31ef5ed1ba1316088939cea399010ed7731dba877ed44aeb407a75ea" +checksum = "7f202df86484c868dbad7eaa557ef785d5c66295e41b460ef922eca0723b842c" [[package]] name = "api-list-common" @@ -94,9 +94,9 @@ version = "0.1.0" [[package]] name = "assert_cmd" -version = "2.1.2" +version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c5bcfa8749ac45dd12cb11055aeeb6b27a3895560d60d71e3c23bf979e60514" +checksum = "9a686bbee5efb88a82df0621b236e74d925f470e5445d3220a5648b892ec99c9" dependencies = [ "anstyle", "bstr", @@ -159,9 +159,9 @@ dependencies = [ [[package]] name = "bumpalo" -version = "3.19.1" +version = "3.20.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5dd9dc738b7a8311c7ade152424974d8115f2cdad61e8dab8dac9f2362298510" +checksum = "5d20789868f4b01b2f2caec9f5c4e0213b41e3e5702a50157d699ae31ced2fcb" [[package]] name = "cast" @@ -171,9 +171,9 @@ checksum = "37b2a672a2cb129a2e41c10b1224bb368f9f37a2b16b612598138befd7b37eb5" [[package]] name = "cc" -version = "1.2.56" +version = "1.2.58" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aebf35691d1bfb0ac386a69bac2fde4dd276fb618cf8bf4f5318fe285e821bb2" +checksum = "e1e928d4b69e3077709075a938a05ffbedfa53a84c8f766efbf8220bb1ff60e1" dependencies = [ "find-msvc-tools", "shlex", @@ -225,9 +225,9 @@ dependencies = [ [[package]] name = "clap" -version = "4.5.58" +version = "4.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "63be97961acde393029492ce0be7a1af7e323e6bae9511ebfac33751be5e6806" +checksum = "b193af5b67834b676abd72466a96c1024e6a6ad978a1f484bd90b85c94041351" dependencies = [ "clap_builder", "clap_derive", @@ -235,9 +235,9 @@ dependencies = [ [[package]] name = "clap_builder" -version = "4.5.58" +version = "4.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f13174bda5dfd69d7e947827e5af4b0f2f94a4a3ee92912fba07a66150f21e2" +checksum = "714a53001bf66416adb0e2ef5ac857140e7dc3a0c48fb28b2f10762fc4b5069f" dependencies = [ "anstream", "anstyle", @@ -247,9 +247,9 @@ dependencies = [ [[package]] name = "clap_derive" -version = "4.5.55" +version = "4.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a92793da1a46a5f2a02a6f4c46c6496b28c43638adea8306fcb0caa1634f24e5" +checksum = "1110bd8a634a1ab8cb04345d8d878267d57c3cf1b38d91b71af6686408bbca6a" dependencies = [ "heck", "proc-macro2", @@ -259,15 +259,15 @@ dependencies = [ [[package]] name = "clap_lex" -version = "1.0.0" +version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3a822ea5bc7590f9d40f1ba12c0dc3c2760f3482c6984db1573ad11031420831" +checksum = "c8d4a3bb8b1e0c1050499d1815f5ab16d04f0959b233085fb31653fbfc9d98f9" [[package]] name = "colorchoice" -version = "1.0.4" +version = "1.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b05b61dc5112cbb17e4b6cd61790d9845d13888356391624cbe7e41efeac1e75" +checksum = "1d07550c9036bf2ae0c684c4297d503f838287c83c53686d05370d0e139ae570" [[package]] name = "compiler_builtins" @@ -278,14 +278,13 @@ dependencies = [ [[package]] name = "console" -version = "0.16.2" +version = "0.16.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "03e45a4a8926227e4197636ba97a9fc9b00477e9f4bd711395687c5f0734bec4" +checksum = "d64e8af5551369d19cf50138de61f1c42074ab970f74e99be916646777f8fc87" dependencies = [ "encode_unicode", "libc", - "once_cell", - "windows-sys 0.61.2", + "windows-sys", ] [[package]] @@ -423,7 +422,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "39cab71617ae0d63f51a36d69f866391735b51691dbda63cf6f96d042b63efeb" dependencies = [ "libc", - "windows-sys 0.61.2", + "windows-sys", ] [[package]] @@ -471,9 +470,9 @@ dependencies = [ [[package]] name = "getrandom" -version = "0.4.1" +version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "139ef39800118c7683f2fd3c98c1b23c09ae076556b435f8e9064ae108aaeeec" +checksum = "0de51e6874e94e7bf76d726fc5d13ba782deca734ff60d5bb2fb2607c7406555" dependencies = [ "cfg-if", "js-sys", @@ -487,12 +486,12 @@ dependencies = [ [[package]] name = "gmp-mpfr-sys" -version = "1.6.8" +version = "1.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "60f8970a75c006bb2f8ae79c6768a116dd215fa8346a87aed99bf9d82ca43394" +checksum = "8cfc928d8ff4ab3767a3674cf55f81186436fb6070866bb1443ffe65a640d2d6" dependencies = [ "libc", - "windows-sys 0.60.2", + "windows-sys", ] [[package]] @@ -611,15 +610,15 @@ dependencies = [ [[package]] name = "itoa" -version = "1.0.17" +version = "1.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "92ecc6618181def0457392ccd0ee51198e065e016d1d527a7ac1b6dc7c1f09d2" +checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682" [[package]] name = "js-sys" -version = "0.3.85" +version = "0.3.94" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8c942ebf8e95485ca0d52d97da7c5a2c387d0e7f0ba4c35e93bfcaee045955b3" +checksum = "2e04e2ef80ce82e13552136fabeef8a5ed1f985a96805761cbb9a2c34e7664d9" dependencies = [ "once_cell", "wasm-bindgen", @@ -633,9 +632,9 @@ checksum = "09edd9e8b54e49e587e4f6295a7d29c3ea94d469cb40ab8ca70b288248a81db2" [[package]] name = "libc" -version = "0.2.182" +version = "0.2.183" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6800badb6cb2082ffd7b6a67e6125bb39f18782f793520caee8cb8846be06112" +checksum = "b5b646652bf6661599e1da8901b3b9522896f01e736bad5f723fe7a3a27f899d" [[package]] name = "libm" @@ -686,9 +685,9 @@ dependencies = [ [[package]] name = "libtest-mimic" -version = "0.8.1" +version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5297962ef19edda4ce33aaa484386e0a5b3d7f2f4e037cbeee00503ef6b29d33" +checksum = "14e6ba06f0ade6e504aff834d7c34298e5155c6baca353cc6a4aaff2f9fd7f33" dependencies = [ "anstream", "anstyle", @@ -698,9 +697,9 @@ dependencies = [ [[package]] name = "linux-raw-sys" -version = "0.11.0" +version = "0.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "df1d3c3b53da64cf5760482273a98e575c651a67eec7f77df96b5b642de8f039" +checksum = "32a66949e030da00e8c7d4434b251670a91556f4144941d37452769c25d58a53" [[package]] name = "log" @@ -766,9 +765,9 @@ dependencies = [ [[package]] name = "once_cell" -version = "1.21.3" +version = "1.21.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d" +checksum = "9f7c3e4beb33f85d45ae3e3a1792185706c8e16d043238c593331cc7cd313b50" [[package]] name = "once_cell_polyfill" @@ -915,18 +914,18 @@ dependencies = [ [[package]] name = "quote" -version = "1.0.44" +version = "1.0.45" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "21b2ebcf727b7760c461f091f9f0f539b77b8e87f2fd88131e7f1b433b3cece4" +checksum = "41f2619966050689382d2b44f664f4bc593e129785a36d6ee376ddf37259b924" dependencies = [ "proc-macro2", ] [[package]] name = "r-efi" -version = "5.3.0" +version = "6.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "69cdb34c158ceb288df11e18b4bd39de994f6657d83847bdffdbd7f346754b0f" +checksum = "f8dcc9c7d52a811697d2151c701e0d08956f92b0e24136cf4cf27b57a6a0d9bf" [[package]] name = "rand" @@ -1009,15 +1008,15 @@ dependencies = [ [[package]] name = "regex-syntax" -version = "0.8.9" +version = "0.8.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a96887878f22d7bad8a3b6dc5b7440e0ada9a245242924394987b21cf2210a4c" +checksum = "dc897dd8d9e8bd1ed8cdad82b5966c3e0ecae09fb1907d58efaa013543185d0a" [[package]] name = "rug" -version = "1.28.1" +version = "1.29.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "de190ec858987c79cad4da30e19e546139b3339331282832af004d0ea7829639" +checksum = "25f6c8f906c90b48e0c1745c9f814c3a31c5eba847043b05c3e9a934dec7c4b3" dependencies = [ "az", "gmp-mpfr-sys", @@ -1046,15 +1045,15 @@ dependencies = [ [[package]] name = "rustix" -version = "1.1.3" +version = "1.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "146c9e247ccc180c1f61615433868c99f3de3ae256a30a43b49f67c2d9171f34" +checksum = "b6fe4565b9518b83ef4f91bb47ce29620ca828bd32cb7e408f0062e9930ba190" dependencies = [ "bitflags", "errno", "libc", "linux-raw-sys", - "windows-sys 0.61.2", + "windows-sys", ] [[package]] @@ -1138,9 +1137,9 @@ checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" [[package]] name = "simd-adler32" -version = "0.3.8" +version = "0.3.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e320a6c5ad31d271ad523dcf3ad13e2767ad8b1cb8f047f75a8aeaf8da139da2" +checksum = "703d5c7ef118737c72f1af64ad2f6f8c5e1921f818cdcb97b8fe6fc69bf66214" [[package]] name = "smallvec" @@ -1169,9 +1168,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.116" +version = "2.0.117" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3df424c70518695237746f84cede799c9c58fcb37450d7b23716568cc8bc69cb" +checksum = "e665b8803e7b1d2a727f4023456bbbbe74da67099c585258af0ad9c5013b9b99" dependencies = [ "proc-macro2", "quote", @@ -1180,15 +1179,15 @@ dependencies = [ [[package]] name = "tempfile" -version = "3.25.0" +version = "3.27.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0136791f7c95b1f6dd99f9cc786b91bb81c3800b639b3478e561ddb7be95e5f1" +checksum = "32497e9a4c7b38532efcdebeef879707aa9f794296a4f0244f6f69e9bc8574bd" dependencies = [ "fastrand", "getrandom", "once_cell", "rustix", - "windows-sys 0.61.2", + "windows-sys", ] [[package]] @@ -1294,9 +1293,9 @@ dependencies = [ [[package]] name = "wasm-bindgen" -version = "0.2.108" +version = "0.2.117" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "64024a30ec1e37399cf85a7ffefebdb72205ca1c972291c51512360d90bd8566" +checksum = "0551fc1bb415591e3372d0bc4780db7e587d84e2a7e79da121051c5c4b89d0b0" dependencies = [ "cfg-if", "once_cell", @@ -1307,9 +1306,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro" -version = "0.2.108" +version = "0.2.117" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "008b239d9c740232e71bd39e8ef6429d27097518b6b30bdf9086833bd5b6d608" +checksum = "7fbdf9a35adf44786aecd5ff89b4563a90325f9da0923236f6104e603c7e86be" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -1317,9 +1316,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.108" +version = "0.2.117" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5256bae2d58f54820e6490f9839c49780dff84c65aeab9e772f15d5f0e913a55" +checksum = "dca9693ef2bab6d4e6707234500350d8dad079eb508dca05530c85dc3a529ff2" dependencies = [ "bumpalo", "proc-macro2", @@ -1330,9 +1329,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-shared" -version = "0.2.108" +version = "0.2.117" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1f01b580c9ac74c8d8f0c0e4afb04eeef2acf145458e52c03845ee9cd23e3d12" +checksum = "39129a682a6d2d841b6c429d0c51e5cb0ed1a03829d8b3d1e69a011e62cb3d3b" dependencies = [ "unicode-ident", ] @@ -1382,9 +1381,9 @@ dependencies = [ [[package]] name = "web-sys" -version = "0.3.85" +version = "0.3.94" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "312e32e551d92129218ea9a2452120f4aabc03529ef03e4d0d82fb2780608598" +checksum = "cd70027e39b12f0849461e08ffc50b9cd7688d942c1c8e3c7b22273236b4dd0a" dependencies = [ "js-sys", "wasm-bindgen", @@ -1422,7 +1421,7 @@ version = "0.1.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c2a7b1c03c876122aa43f3020e6c3c3ee5c05081c9a00739faf7503aeba10d22" dependencies = [ - "windows-sys 0.61.2", + "windows-sys", ] [[package]] @@ -1437,15 +1436,6 @@ version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5" -[[package]] -name = "windows-sys" -version = "0.60.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f2f500e4d28234f72040990ec9d39e3a6b950f9f22d3dba18416c35882612bcb" -dependencies = [ - "windows-targets", -] - [[package]] name = "windows-sys" version = "0.61.2" @@ -1455,71 +1445,6 @@ dependencies = [ "windows-link", ] -[[package]] -name = "windows-targets" -version = "0.53.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4945f9f551b88e0d65f3db0bc25c33b8acea4d9e41163edf90dcd0b19f9069f3" -dependencies = [ - "windows-link", - "windows_aarch64_gnullvm", - "windows_aarch64_msvc", - "windows_i686_gnu", - "windows_i686_gnullvm", - "windows_i686_msvc", - "windows_x86_64_gnu", - "windows_x86_64_gnullvm", - "windows_x86_64_msvc", -] - -[[package]] -name = "windows_aarch64_gnullvm" -version = "0.53.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a9d8416fa8b42f5c947f8482c43e7d89e73a173cead56d044f6a56104a6d1b53" - -[[package]] -name = "windows_aarch64_msvc" -version = "0.53.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b9d782e804c2f632e395708e99a94275910eb9100b2114651e04744e9b125006" - -[[package]] -name = "windows_i686_gnu" -version = "0.53.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "960e6da069d81e09becb0ca57a65220ddff016ff2d6af6a223cf372a506593a3" - -[[package]] -name = "windows_i686_gnullvm" -version = "0.53.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fa7359d10048f68ab8b09fa71c3daccfb0e9b559aed648a8f95469c27057180c" - -[[package]] -name = "windows_i686_msvc" -version = "0.53.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e7ac75179f18232fe9c285163565a57ef8d3c89254a30685b57d83a38d326c2" - -[[package]] -name = "windows_x86_64_gnu" -version = "0.53.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c3842cdd74a865a8066ab39c8a7a473c0778a3f29370b5fd6b4b9aa7df4a499" - -[[package]] -name = "windows_x86_64_gnullvm" -version = "0.53.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0ffa179e2d07eee8ad8f57493436566c7cc30ac536a3379fdf008f47f6bb7ae1" - -[[package]] -name = "windows_x86_64_msvc" -version = "0.53.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d6bbff5f0aada427a1e5a6da5f1f98158182f26556f345ac9e04d36d0ebed650" - [[package]] name = "wit-bindgen" version = "0.51.0" @@ -1610,18 +1535,18 @@ dependencies = [ [[package]] name = "zerocopy" -version = "0.8.39" +version = "0.8.48" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "db6d35d663eadb6c932438e763b262fe1a70987f9ae936e60158176d710cae4a" +checksum = "eed437bf9d6692032087e337407a86f04cd8d6a16a37199ed57949d415bd68e9" dependencies = [ "zerocopy-derive", ] [[package]] name = "zerocopy-derive" -version = "0.8.39" +version = "0.8.48" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4122cd3169e94605190e77839c9a40d40ed048d305bfdc146e7df40ab0f3e517" +checksum = "70e3cd084b1788766f53af483dd21f93881ff30d7320490ec3ef7526d203bad4" dependencies = [ "proc-macro2", "quote", From fc47fbcf511aa43ef69c7de4f2c32cd6c6d17527 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Wed, 1 Apr 2026 08:51:03 -0400 Subject: [PATCH 084/183] ci: Don't re-archive the tar.xz benchmark baseline The new version of `actions/upload-artifact` allows for skipping the automatic file zipping, which is good because our files are already compressed. --- library/compiler-builtins/.github/workflows/main.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/library/compiler-builtins/.github/workflows/main.yaml b/library/compiler-builtins/.github/workflows/main.yaml index 83eac57fd9452..0ed79de96f885 100644 --- a/library/compiler-builtins/.github/workflows/main.yaml +++ b/library/compiler-builtins/.github/workflows/main.yaml @@ -320,6 +320,7 @@ jobs: with: name: ${{ env.BASELINE_NAME }} path: ${{ env.BASELINE_NAME }}.tar.xz + archive: false # already compressed - name: Print test logs if available if: always() From 6b97e039e4fc90500b03e7676b2c9d8a07105f78 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Tue, 31 Mar 2026 17:50:35 -0400 Subject: [PATCH 085/183] c-b: Replace the `no-asm` feature with an opposite-polarity `arch` Make `libm` and `compiler-builtins` use the same configuration: * By default there is an `arch` feature which allows `core::arch` and inline assembly. * Disabling the `arch` feature turns these off. Positive feature flags are easier to reason about than negative, so this will allow for some build script cleanup as well. --- .../compiler-builtins/builtins-shim/Cargo.toml | 11 +++++------ .../compiler-builtins/builtins-test/Cargo.toml | 12 ++++-------- library/compiler-builtins/ci/bench-icount.sh | 2 +- library/compiler-builtins/ci/miri.sh | 5 +++-- library/compiler-builtins/ci/run.sh | 8 ++++---- .../compiler-builtins/Cargo.toml | 11 +++++------ .../compiler-builtins/compiler-builtins/build.rs | 2 +- .../src/int/specialized_div_rem/mod.rs | 16 ++++++++-------- .../compiler-builtins/src/mem/mod.rs | 5 +---- library/compiler-builtins/libm-test/Cargo.toml | 4 +++- 10 files changed, 35 insertions(+), 41 deletions(-) diff --git a/library/compiler-builtins/builtins-shim/Cargo.toml b/library/compiler-builtins/builtins-shim/Cargo.toml index 0ff2acdbbe6a2..c940723a1ba5f 100644 --- a/library/compiler-builtins/builtins-shim/Cargo.toml +++ b/library/compiler-builtins/builtins-shim/Cargo.toml @@ -39,17 +39,16 @@ test = false cc = { version = "1.2", optional = true } [features] -default = [] +default = ["arch"] + +# Enable architecture-specific features such as SIMD or assembly routines. If +# disabled, the generic version can be tested on any platform. +arch = [] # Enable compilation of C code in compiler-rt, filling in some more optimized # implementations and also filling in unimplemented intrinsics c = ["dep:cc"] -# For implementations where there is both a generic version and a platform- -# specific version, use the generic version. This is meant to enable testing -# the generic versions on all platforms. -no-asm = [] - # Flag this library as the unstable compiler-builtins lib. This must be enabled # when using as `std`'s dependency.' compiler-builtins = ["unmangled-names"] diff --git a/library/compiler-builtins/builtins-test/Cargo.toml b/library/compiler-builtins/builtins-test/Cargo.toml index 1b356b102c19d..f1a5be415675d 100644 --- a/library/compiler-builtins/builtins-test/Cargo.toml +++ b/library/compiler-builtins/builtins-test/Cargo.toml @@ -6,7 +6,7 @@ publish = false license = "MIT AND Apache-2.0 WITH LLVM-exception AND (MIT OR Apache-2.0)" [dependencies] -compiler_builtins = { workspace = true, features = ["unstable-public-internals"] } +compiler_builtins = { workspace = true, default-features = false, features = ["unstable-public-internals"] } # For fuzzing tests we want a deterministic seedable RNG. We also eliminate potential # problems with system RNGs on the variety of platforms this crate is tested on. @@ -24,9 +24,10 @@ gungraun = { workspace = true, optional = true } paste.workspace = true [features] -default = [] +# Defaults should match the defaults in compiler-builtins since we have that +# dependency with `default-features=false`. +default = ["compiler_builtins/arch"] c = ["compiler_builtins/c"] -no-asm = ["compiler_builtins/no-asm"] # Enable icount benchmarks (requires gungraun-runner and valgrind locally) icount = ["dep:gungraun"] @@ -36,11 +37,6 @@ icount = ["dep:gungraun"] benchmarking-reports = ["walltime", "criterion/plotters", "criterion/html_reports"] walltime = ["dep:criterion"] -# NOTE: benchmarks must be run with `--no-default-features` or with -# `-p builtins-test`, otherwise the default `compiler-builtins` feature -# of the `compiler_builtins` crate gets activated, resulting in linker -# errors. - [[bench]] name = "float_add" harness = false diff --git a/library/compiler-builtins/ci/bench-icount.sh b/library/compiler-builtins/ci/bench-icount.sh index e24a47fe07be7..17b6997602dab 100755 --- a/library/compiler-builtins/ci/bench-icount.sh +++ b/library/compiler-builtins/ci/bench-icount.sh @@ -79,7 +79,7 @@ function run_icount_benchmarks() { # Run once with softfloats, once with arch instructions enabled run_icount_benchmarks --features force-soft-floats -- --save-baseline=softfloat -run_icount_benchmarks -- --save-baseline=hardfloat +run_icount_benchmarks --features arch -- --save-baseline=hardfloat if [ "$failed" != "0" ]; then echo "One or more benchmarks failed" diff --git a/library/compiler-builtins/ci/miri.sh b/library/compiler-builtins/ci/miri.sh index aae474d884638..90b64934db0b5 100755 --- a/library/compiler-builtins/ci/miri.sh +++ b/library/compiler-builtins/ci/miri.sh @@ -13,10 +13,11 @@ targets=( s390x-unknown-linux-gnu ) for target in "${targets[@]}"; do - # Only run the `mem` tests to avoid this taking too long. + # Only run the `mem` tests to avoid this taking too long. Disable default + # features to turn off `arch` and avoid inline assembly. cargo miri test \ --manifest-path builtins-test/Cargo.toml \ - --features no-asm \ + --no-default-features \ --target "$target" \ -- mem done diff --git a/library/compiler-builtins/ci/run.sh b/library/compiler-builtins/ci/run.sh index 5ddfbd038f5c5..021bc6809e43f 100755 --- a/library/compiler-builtins/ci/run.sh +++ b/library/compiler-builtins/ci/run.sh @@ -55,10 +55,10 @@ else "${test_builtins[@]}" --release "${test_builtins[@]}" --features c "${test_builtins[@]}" --features c --release - "${test_builtins[@]}" --features no-asm - "${test_builtins[@]}" --features no-asm --release "${test_builtins[@]}" --benches "${test_builtins[@]}" --benches --release + "${test_builtins[@]}" --no-default-features + "${test_builtins[@]}" --no-default-features --release # Validate that having a verbatim path for the target directory works # (trivial to regress using `/` in paths to build artifacts rather than @@ -85,8 +85,8 @@ symcheck_cb_args=(-- --package compiler_builtins --features compiler-builtins) "${symcheck[@]}" "${symcheck_cb_args[@]}" --release "${symcheck[@]}" "${symcheck_cb_args[@]}" --features c "${symcheck[@]}" "${symcheck_cb_args[@]}" --features c --release -"${symcheck[@]}" "${symcheck_cb_args[@]}" --features no-asm -"${symcheck[@]}" "${symcheck_cb_args[@]}" --features no-asm --release +"${symcheck[@]}" "${symcheck_cb_args[@]}" --no-default-features +"${symcheck[@]}" "${symcheck_cb_args[@]}" --no-default-features --release run_intrinsics_test() { build_args=(--verbose --manifest-path builtins-test-intrinsics/Cargo.toml) diff --git a/library/compiler-builtins/compiler-builtins/Cargo.toml b/library/compiler-builtins/compiler-builtins/Cargo.toml index 2299ae8e3aaf3..aa4e8d2ab2850 100644 --- a/library/compiler-builtins/compiler-builtins/Cargo.toml +++ b/library/compiler-builtins/compiler-builtins/Cargo.toml @@ -34,17 +34,16 @@ core = { path = "../../core", optional = true } cc = { version = "1.2", optional = true } [features] -default = [] +default = ["arch"] + +# Enable architecture-specific features such as SIMD or assembly routines. If +# disabled, the generic version can be tested on any platform. +arch = [] # Enable compilation of C code in compiler-rt, filling in some more optimized # implementations and also filling in unimplemented intrinsics c = ["dep:cc"] -# For implementations where there is both a generic version and a platform- -# specific version, use the generic version. This is meant to enable testing -# the generic versions on all platforms. -no-asm = [] - # Flag this library as the unstable compiler-builtins lib. This must be enabled # when using as `std`'s dependency.' compiler-builtins = ["dep:core", "unmangled-names"] diff --git a/library/compiler-builtins/compiler-builtins/build.rs b/library/compiler-builtins/compiler-builtins/build.rs index 3b1ad344e2a30..bdbc766de8472 100644 --- a/library/compiler-builtins/compiler-builtins/build.rs +++ b/library/compiler-builtins/compiler-builtins/build.rs @@ -90,7 +90,7 @@ fn configure_libm(target: &Target) { set_cfg("intrinsics_enabled", true); // The arch module may contain assembly. - set_cfg("arch_enabled", !cfg!(feature = "no-asm")); + set_cfg("arch_enabled", cfg!(feature = "arch")); let opt = !matches!(target.opt_level.as_str(), "0" | "1"); set_cfg("optimizations_enabled", opt); diff --git a/library/compiler-builtins/compiler-builtins/src/int/specialized_div_rem/mod.rs b/library/compiler-builtins/compiler-builtins/src/int/specialized_div_rem/mod.rs index 5ffe1f59b4db6..902c191d65285 100644 --- a/library/compiler-builtins/compiler-builtins/src/int/specialized_div_rem/mod.rs +++ b/library/compiler-builtins/compiler-builtins/src/int/specialized_div_rem/mod.rs @@ -144,7 +144,7 @@ fn u64_by_u64_div_rem(duo: u64, div: u64) -> (u64, u64) { target_family = "wasm", not(any(target_pointer_width = "16", target_pointer_width = "32")), ), - not(all(not(feature = "no-asm"), target_arch = "x86_64")), + not(all(feature = "arch", target_arch = "x86_64")), not(any(target_arch = "sparc", target_arch = "sparc64")) ))] impl_trifecta!( @@ -165,7 +165,7 @@ impl_trifecta!( target_family = "wasm", not(any(target_pointer_width = "16", target_pointer_width = "32")), )), - not(all(not(feature = "no-asm"), target_arch = "x86_64")), + not(all(feature = "arch", target_arch = "x86_64")), not(any(target_arch = "sparc", target_arch = "sparc64")) ))] impl_delegate!( @@ -186,7 +186,7 @@ impl_delegate!( /// /// If the quotient does not fit in a `u64`, a floating point exception occurs. /// If `div == 0`, then a division by zero exception occurs. -#[cfg(all(not(feature = "no-asm"), target_arch = "x86_64"))] +#[cfg(all(feature = "arch", target_arch = "x86_64"))] #[inline] unsafe fn u128_by_u64_div_rem(duo: u128, div: u64) -> (u64, u64) { let duo_lo = duo as u64; @@ -208,7 +208,7 @@ unsafe fn u128_by_u64_div_rem(duo: u128, div: u64) -> (u64, u64) { } // use `asymmetric` instead of `trifecta` on x86_64 -#[cfg(all(not(feature = "no-asm"), target_arch = "x86_64"))] +#[cfg(all(feature = "arch", target_arch = "x86_64"))] impl_asymmetric!( u128_div_rem, zero_div_fn, @@ -237,7 +237,7 @@ fn u32_by_u32_div_rem(duo: u32, div: u32) -> (u32, u32) { // When not on x86 and the pointer width is not 64, use `delegate` since the division size is larger // than register size. #[cfg(all( - not(all(not(feature = "no-asm"), target_arch = "x86")), + not(all(feature = "arch", target_arch = "x86")), not(target_pointer_width = "64") ))] impl_delegate!( @@ -254,7 +254,7 @@ impl_delegate!( // When not on x86 and the pointer width is 64, use `binary_long`. #[cfg(all( - not(all(not(feature = "no-asm"), target_arch = "x86")), + not(all(feature = "arch", target_arch = "x86")), target_pointer_width = "64" ))] impl_binary_long!( @@ -272,7 +272,7 @@ impl_binary_long!( /// /// If the quotient does not fit in a `u32`, a floating point exception occurs. /// If `div == 0`, then a division by zero exception occurs. -#[cfg(all(not(feature = "no-asm"), target_arch = "x86"))] +#[cfg(all(feature = "arch", target_arch = "x86"))] #[inline] unsafe fn u64_by_u32_div_rem(duo: u64, div: u32) -> (u32, u32) { let duo_lo = duo as u32; @@ -294,7 +294,7 @@ unsafe fn u64_by_u32_div_rem(duo: u64, div: u32) -> (u32, u32) { } // use `asymmetric` instead of `delegate` on x86 -#[cfg(all(not(feature = "no-asm"), target_arch = "x86"))] +#[cfg(all(feature = "arch", target_arch = "x86"))] impl_asymmetric!( u64_div_rem, zero_div_fn, diff --git a/library/compiler-builtins/compiler-builtins/src/mem/mod.rs b/library/compiler-builtins/compiler-builtins/src/mem/mod.rs index a227f60a2949b..ac41cd33416f6 100644 --- a/library/compiler-builtins/compiler-builtins/src/mem/mod.rs +++ b/library/compiler-builtins/compiler-builtins/src/mem/mod.rs @@ -4,10 +4,7 @@ #![allow(unsafe_op_in_unsafe_fn)] // memcpy/memmove/memset have optimized implementations on some architectures -#[cfg_attr( - all(not(feature = "no-asm"), target_arch = "x86_64"), - path = "x86_64.rs" -)] +#[cfg_attr(all(feature = "arch", target_arch = "x86_64"), path = "x86_64.rs")] mod impls; intrinsics! { diff --git a/library/compiler-builtins/libm-test/Cargo.toml b/library/compiler-builtins/libm-test/Cargo.toml index abc9bc6f75e11..9314c26831eba 100644 --- a/library/compiler-builtins/libm-test/Cargo.toml +++ b/library/compiler-builtins/libm-test/Cargo.toml @@ -36,7 +36,9 @@ rand = { workspace = true, optional = true } libtest-mimic.workspace = true [features] -default = ["build-mpfr", "unstable-float"] +# Defaults should match the defaults in compiler-builtins since we have that +# dependency with `default-features=false`. +default = ["build-mpfr", "unstable-float", "compiler_builtins/arch"] # Propagated from libm because this affects which functions we test. unstable-float = ["libm/unstable-float", "rug?/nightly-float"] From 2f57167feb698c1126697edd719420a6618d875b Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Wed, 1 Apr 2026 20:13:42 +0000 Subject: [PATCH 086/183] Revert "ci: Don't re-archive the tar.xz benchmark baseline" Unfortunately the `gh` CLI tool can't yet download non-zipped archives. Attempting to do so says: error downloading baseline-icount-i686-202604011355-ba4c48868cad.tar.xz: error extracting zip archive: zip: not a valid zip file Drop this change until the CLI is updated. This reverts commit 0a57b9e3eda70c3673815fc47fad137a3c62da98. --- library/compiler-builtins/.github/workflows/main.yaml | 1 - 1 file changed, 1 deletion(-) diff --git a/library/compiler-builtins/.github/workflows/main.yaml b/library/compiler-builtins/.github/workflows/main.yaml index 0ed79de96f885..83eac57fd9452 100644 --- a/library/compiler-builtins/.github/workflows/main.yaml +++ b/library/compiler-builtins/.github/workflows/main.yaml @@ -320,7 +320,6 @@ jobs: with: name: ${{ env.BASELINE_NAME }} path: ${{ env.BASELINE_NAME }}.tar.xz - archive: false # already compressed - name: Print test logs if available if: always() From 5448797944c754789c140f017177ad201a4595db Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Wed, 1 Apr 2026 16:29:56 -0400 Subject: [PATCH 087/183] ci: Bump ubuntu:25.10 docker images to 26.04 --- .../ci/docker/aarch64-unknown-linux-gnu/Dockerfile | 2 +- .../ci/docker/arm-unknown-linux-gnueabi/Dockerfile | 2 +- .../ci/docker/arm-unknown-linux-gnueabihf/Dockerfile | 2 +- .../ci/docker/armv7-unknown-linux-gnueabihf/Dockerfile | 2 +- .../ci/docker/i586-unknown-linux-gnu/Dockerfile | 2 +- .../ci/docker/i686-unknown-linux-gnu/Dockerfile | 2 +- .../ci/docker/loongarch64-unknown-linux-gnu/Dockerfile | 2 +- .../ci/docker/mips-unknown-linux-gnu/Dockerfile | 2 +- .../ci/docker/mips64-unknown-linux-gnuabi64/Dockerfile | 2 +- .../ci/docker/mips64el-unknown-linux-gnuabi64/Dockerfile | 2 +- .../ci/docker/mipsel-unknown-linux-gnu/Dockerfile | 2 +- .../ci/docker/powerpc-unknown-linux-gnu/Dockerfile | 2 +- .../ci/docker/powerpc64-unknown-linux-gnu/Dockerfile | 2 +- .../ci/docker/powerpc64le-unknown-linux-gnu/Dockerfile | 2 +- .../ci/docker/riscv64gc-unknown-linux-gnu/Dockerfile | 4 ++-- .../compiler-builtins/ci/docker/thumbv6m-none-eabi/Dockerfile | 2 +- .../ci/docker/thumbv7em-none-eabi/Dockerfile | 2 +- .../ci/docker/thumbv7em-none-eabihf/Dockerfile | 2 +- .../compiler-builtins/ci/docker/thumbv7m-none-eabi/Dockerfile | 2 +- .../ci/docker/wasm32-unknown-unknown/Dockerfile | 2 +- .../ci/docker/x86_64-unknown-linux-gnu/Dockerfile | 2 +- library/compiler-builtins/ci/run-docker.sh | 2 +- 22 files changed, 23 insertions(+), 23 deletions(-) diff --git a/library/compiler-builtins/ci/docker/aarch64-unknown-linux-gnu/Dockerfile b/library/compiler-builtins/ci/docker/aarch64-unknown-linux-gnu/Dockerfile index 683bd07fd47ef..30a13fc5de910 100644 --- a/library/compiler-builtins/ci/docker/aarch64-unknown-linux-gnu/Dockerfile +++ b/library/compiler-builtins/ci/docker/aarch64-unknown-linux-gnu/Dockerfile @@ -1,4 +1,4 @@ -ARG IMAGE=ubuntu:25.10 +ARG IMAGE=ubuntu:26.04 FROM $IMAGE RUN apt-get update && \ diff --git a/library/compiler-builtins/ci/docker/arm-unknown-linux-gnueabi/Dockerfile b/library/compiler-builtins/ci/docker/arm-unknown-linux-gnueabi/Dockerfile index 781abd1b6e888..41ff36a49e3bb 100644 --- a/library/compiler-builtins/ci/docker/arm-unknown-linux-gnueabi/Dockerfile +++ b/library/compiler-builtins/ci/docker/arm-unknown-linux-gnueabi/Dockerfile @@ -1,4 +1,4 @@ -ARG IMAGE=ubuntu:25.10 +ARG IMAGE=ubuntu:26.04 FROM $IMAGE RUN apt-get update && \ diff --git a/library/compiler-builtins/ci/docker/arm-unknown-linux-gnueabihf/Dockerfile b/library/compiler-builtins/ci/docker/arm-unknown-linux-gnueabihf/Dockerfile index 36ea4827dc52f..1fad72c470f03 100644 --- a/library/compiler-builtins/ci/docker/arm-unknown-linux-gnueabihf/Dockerfile +++ b/library/compiler-builtins/ci/docker/arm-unknown-linux-gnueabihf/Dockerfile @@ -1,4 +1,4 @@ -ARG IMAGE=ubuntu:25.10 +ARG IMAGE=ubuntu:26.04 FROM $IMAGE RUN apt-get update && \ diff --git a/library/compiler-builtins/ci/docker/armv7-unknown-linux-gnueabihf/Dockerfile b/library/compiler-builtins/ci/docker/armv7-unknown-linux-gnueabihf/Dockerfile index 8b76693b2799e..039ccd5745256 100644 --- a/library/compiler-builtins/ci/docker/armv7-unknown-linux-gnueabihf/Dockerfile +++ b/library/compiler-builtins/ci/docker/armv7-unknown-linux-gnueabihf/Dockerfile @@ -1,4 +1,4 @@ -ARG IMAGE=ubuntu:25.10 +ARG IMAGE=ubuntu:26.04 FROM $IMAGE RUN apt-get update && \ diff --git a/library/compiler-builtins/ci/docker/i586-unknown-linux-gnu/Dockerfile b/library/compiler-builtins/ci/docker/i586-unknown-linux-gnu/Dockerfile index 9125038acbde5..9319e73dd03f0 100644 --- a/library/compiler-builtins/ci/docker/i586-unknown-linux-gnu/Dockerfile +++ b/library/compiler-builtins/ci/docker/i586-unknown-linux-gnu/Dockerfile @@ -1,4 +1,4 @@ -ARG IMAGE=ubuntu:25.10 +ARG IMAGE=ubuntu:26.04 FROM $IMAGE RUN apt-get update && \ diff --git a/library/compiler-builtins/ci/docker/i686-unknown-linux-gnu/Dockerfile b/library/compiler-builtins/ci/docker/i686-unknown-linux-gnu/Dockerfile index 9125038acbde5..9319e73dd03f0 100644 --- a/library/compiler-builtins/ci/docker/i686-unknown-linux-gnu/Dockerfile +++ b/library/compiler-builtins/ci/docker/i686-unknown-linux-gnu/Dockerfile @@ -1,4 +1,4 @@ -ARG IMAGE=ubuntu:25.10 +ARG IMAGE=ubuntu:26.04 FROM $IMAGE RUN apt-get update && \ diff --git a/library/compiler-builtins/ci/docker/loongarch64-unknown-linux-gnu/Dockerfile b/library/compiler-builtins/ci/docker/loongarch64-unknown-linux-gnu/Dockerfile index a652235958777..442a13164880c 100644 --- a/library/compiler-builtins/ci/docker/loongarch64-unknown-linux-gnu/Dockerfile +++ b/library/compiler-builtins/ci/docker/loongarch64-unknown-linux-gnu/Dockerfile @@ -1,4 +1,4 @@ -ARG IMAGE=ubuntu:25.10 +ARG IMAGE=ubuntu:26.04 FROM $IMAGE RUN apt-get update && \ diff --git a/library/compiler-builtins/ci/docker/mips-unknown-linux-gnu/Dockerfile b/library/compiler-builtins/ci/docker/mips-unknown-linux-gnu/Dockerfile index 0913f33c05ce4..9941a8c2736c0 100644 --- a/library/compiler-builtins/ci/docker/mips-unknown-linux-gnu/Dockerfile +++ b/library/compiler-builtins/ci/docker/mips-unknown-linux-gnu/Dockerfile @@ -1,4 +1,4 @@ -ARG IMAGE=ubuntu:25.10 +ARG IMAGE=ubuntu:26.04 FROM $IMAGE RUN apt-get update && \ diff --git a/library/compiler-builtins/ci/docker/mips64-unknown-linux-gnuabi64/Dockerfile b/library/compiler-builtins/ci/docker/mips64-unknown-linux-gnuabi64/Dockerfile index d2f4e484b1aab..c20d0a77b81c3 100644 --- a/library/compiler-builtins/ci/docker/mips64-unknown-linux-gnuabi64/Dockerfile +++ b/library/compiler-builtins/ci/docker/mips64-unknown-linux-gnuabi64/Dockerfile @@ -1,4 +1,4 @@ -ARG IMAGE=ubuntu:25.10 +ARG IMAGE=ubuntu:26.04 FROM $IMAGE RUN apt-get update && \ diff --git a/library/compiler-builtins/ci/docker/mips64el-unknown-linux-gnuabi64/Dockerfile b/library/compiler-builtins/ci/docker/mips64el-unknown-linux-gnuabi64/Dockerfile index 873754b2793e9..584f7ffff45a5 100644 --- a/library/compiler-builtins/ci/docker/mips64el-unknown-linux-gnuabi64/Dockerfile +++ b/library/compiler-builtins/ci/docker/mips64el-unknown-linux-gnuabi64/Dockerfile @@ -1,4 +1,4 @@ -ARG IMAGE=ubuntu:25.10 +ARG IMAGE=ubuntu:26.04 FROM $IMAGE RUN apt-get update && \ diff --git a/library/compiler-builtins/ci/docker/mipsel-unknown-linux-gnu/Dockerfile b/library/compiler-builtins/ci/docker/mipsel-unknown-linux-gnu/Dockerfile index 5768b68d6c950..ead99bb9c1132 100644 --- a/library/compiler-builtins/ci/docker/mipsel-unknown-linux-gnu/Dockerfile +++ b/library/compiler-builtins/ci/docker/mipsel-unknown-linux-gnu/Dockerfile @@ -1,4 +1,4 @@ -ARG IMAGE=ubuntu:25.10 +ARG IMAGE=ubuntu:26.04 FROM $IMAGE RUN apt-get update && \ diff --git a/library/compiler-builtins/ci/docker/powerpc-unknown-linux-gnu/Dockerfile b/library/compiler-builtins/ci/docker/powerpc-unknown-linux-gnu/Dockerfile index c625a4bcd5d7c..74071874ed7cf 100644 --- a/library/compiler-builtins/ci/docker/powerpc-unknown-linux-gnu/Dockerfile +++ b/library/compiler-builtins/ci/docker/powerpc-unknown-linux-gnu/Dockerfile @@ -1,4 +1,4 @@ -ARG IMAGE=ubuntu:25.10 +ARG IMAGE=ubuntu:26.04 FROM $IMAGE RUN apt-get update && \ diff --git a/library/compiler-builtins/ci/docker/powerpc64-unknown-linux-gnu/Dockerfile b/library/compiler-builtins/ci/docker/powerpc64-unknown-linux-gnu/Dockerfile index 86a7a8cd46e4e..ba4fec7160b64 100644 --- a/library/compiler-builtins/ci/docker/powerpc64-unknown-linux-gnu/Dockerfile +++ b/library/compiler-builtins/ci/docker/powerpc64-unknown-linux-gnu/Dockerfile @@ -1,4 +1,4 @@ -ARG IMAGE=ubuntu:25.10 +ARG IMAGE=ubuntu:26.04 FROM $IMAGE RUN apt-get update && \ diff --git a/library/compiler-builtins/ci/docker/powerpc64le-unknown-linux-gnu/Dockerfile b/library/compiler-builtins/ci/docker/powerpc64le-unknown-linux-gnu/Dockerfile index 722b10b0a7349..e90d4c8812042 100644 --- a/library/compiler-builtins/ci/docker/powerpc64le-unknown-linux-gnu/Dockerfile +++ b/library/compiler-builtins/ci/docker/powerpc64le-unknown-linux-gnu/Dockerfile @@ -1,4 +1,4 @@ -ARG IMAGE=ubuntu:25.10 +ARG IMAGE=ubuntu:26.04 FROM $IMAGE RUN apt-get update && \ diff --git a/library/compiler-builtins/ci/docker/riscv64gc-unknown-linux-gnu/Dockerfile b/library/compiler-builtins/ci/docker/riscv64gc-unknown-linux-gnu/Dockerfile index 7a721ba05416e..96442121bcd9e 100644 --- a/library/compiler-builtins/ci/docker/riscv64gc-unknown-linux-gnu/Dockerfile +++ b/library/compiler-builtins/ci/docker/riscv64gc-unknown-linux-gnu/Dockerfile @@ -1,11 +1,11 @@ -ARG IMAGE=ubuntu:25.10 +ARG IMAGE=ubuntu:26.04 FROM $IMAGE RUN apt-get update && \ apt-get install -y --no-install-recommends \ gcc libc6-dev qemu-user ca-certificates \ gcc-riscv64-linux-gnu libc6-dev-riscv64-cross \ - qemu-system-riscv64 + qemu-system-riscv ENV TOOLCHAIN_PREFIX=riscv64-linux-gnu- ENV CARGO_TARGET_RISCV64GC_UNKNOWN_LINUX_GNU_LINKER="$TOOLCHAIN_PREFIX"gcc \ diff --git a/library/compiler-builtins/ci/docker/thumbv6m-none-eabi/Dockerfile b/library/compiler-builtins/ci/docker/thumbv6m-none-eabi/Dockerfile index a1a6b3cf5cfd2..463cce94e5540 100644 --- a/library/compiler-builtins/ci/docker/thumbv6m-none-eabi/Dockerfile +++ b/library/compiler-builtins/ci/docker/thumbv6m-none-eabi/Dockerfile @@ -1,4 +1,4 @@ -ARG IMAGE=ubuntu:25.10 +ARG IMAGE=ubuntu:26.04 FROM $IMAGE RUN apt-get update && \ diff --git a/library/compiler-builtins/ci/docker/thumbv7em-none-eabi/Dockerfile b/library/compiler-builtins/ci/docker/thumbv7em-none-eabi/Dockerfile index a1a6b3cf5cfd2..463cce94e5540 100644 --- a/library/compiler-builtins/ci/docker/thumbv7em-none-eabi/Dockerfile +++ b/library/compiler-builtins/ci/docker/thumbv7em-none-eabi/Dockerfile @@ -1,4 +1,4 @@ -ARG IMAGE=ubuntu:25.10 +ARG IMAGE=ubuntu:26.04 FROM $IMAGE RUN apt-get update && \ diff --git a/library/compiler-builtins/ci/docker/thumbv7em-none-eabihf/Dockerfile b/library/compiler-builtins/ci/docker/thumbv7em-none-eabihf/Dockerfile index a1a6b3cf5cfd2..463cce94e5540 100644 --- a/library/compiler-builtins/ci/docker/thumbv7em-none-eabihf/Dockerfile +++ b/library/compiler-builtins/ci/docker/thumbv7em-none-eabihf/Dockerfile @@ -1,4 +1,4 @@ -ARG IMAGE=ubuntu:25.10 +ARG IMAGE=ubuntu:26.04 FROM $IMAGE RUN apt-get update && \ diff --git a/library/compiler-builtins/ci/docker/thumbv7m-none-eabi/Dockerfile b/library/compiler-builtins/ci/docker/thumbv7m-none-eabi/Dockerfile index a1a6b3cf5cfd2..463cce94e5540 100644 --- a/library/compiler-builtins/ci/docker/thumbv7m-none-eabi/Dockerfile +++ b/library/compiler-builtins/ci/docker/thumbv7m-none-eabi/Dockerfile @@ -1,4 +1,4 @@ -ARG IMAGE=ubuntu:25.10 +ARG IMAGE=ubuntu:26.04 FROM $IMAGE RUN apt-get update && \ diff --git a/library/compiler-builtins/ci/docker/wasm32-unknown-unknown/Dockerfile b/library/compiler-builtins/ci/docker/wasm32-unknown-unknown/Dockerfile index b646a72bb37cc..09f35c3b128d0 100644 --- a/library/compiler-builtins/ci/docker/wasm32-unknown-unknown/Dockerfile +++ b/library/compiler-builtins/ci/docker/wasm32-unknown-unknown/Dockerfile @@ -1,4 +1,4 @@ -ARG IMAGE=ubuntu:25.10 +ARG IMAGE=ubuntu:26.04 FROM $IMAGE RUN apt-get update && \ diff --git a/library/compiler-builtins/ci/docker/x86_64-unknown-linux-gnu/Dockerfile b/library/compiler-builtins/ci/docker/x86_64-unknown-linux-gnu/Dockerfile index 927515f90f329..103c395ee8496 100644 --- a/library/compiler-builtins/ci/docker/x86_64-unknown-linux-gnu/Dockerfile +++ b/library/compiler-builtins/ci/docker/x86_64-unknown-linux-gnu/Dockerfile @@ -1,4 +1,4 @@ -ARG IMAGE=ubuntu:25.10 +ARG IMAGE=ubuntu:26.04 FROM $IMAGE RUN apt-get update && \ diff --git a/library/compiler-builtins/ci/run-docker.sh b/library/compiler-builtins/ci/run-docker.sh index 619e1a02359c2..a894677b59f90 100755 --- a/library/compiler-builtins/ci/run-docker.sh +++ b/library/compiler-builtins/ci/run-docker.sh @@ -98,7 +98,7 @@ if [ "${1:-}" = "--help" ] || [ "$#" -gt 1 ]; then usage: ./ci/run-docker.sh [target] you can also set DOCKER_BASE_IMAGE to use something other than the default - ubuntu:25.10 (or rustlang/rust:nightly). + ubuntu:26.04 (or rustlang/rust:nightly). " exit fi From dee26f70d1f6b0aca58c6b04c92805bfaf6db0c9 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Tue, 31 Mar 2026 21:35:33 -0400 Subject: [PATCH 088/183] libm: Deprecate `feature = "force-soft-float"` This was needed while some codegen backends did not support inline assembly, or ran into circular issues using vector intrinsics. All such issues have since been resolved with the in-tree backends. The remaining need was to be able to toggle these features in tests, which we can do via the enabled-by-default `arch` feature. Since there aren't any cases requiring `force-soft-float`, remove its functionality and deprecate it. It is possible that future codegen backends may have a similar need to disable inline assembly until pairity with the LLVM backend can be reached. In these cases rather than having `force-soft-float`, it would be better to have rustc provide a `cfg(target_supports_inline_asm)`. `build.rs` can then do something like: let nightly = cfg!(feature = "compiler-builtins") || cfg!(feature = "unstable"); let asm_support = env::var("CARGO_CFG_TARGET_SUPPORTS_INLINE_ASM").is_ok(); let arch_enabled = cfg!(feature = "arch") && (!nightly || (nightly && asm_support)); set_cfg("arch_enabled", arch_enabled); This is about what we have now with `cfg(target_has_reliable_f16)` and `cfg(target_has_reliable_f128)` being set by rustc, which is significantly easier to use than the `feature = "no-f16-f128"` that it replaced. Having rustc directly tell us what it supports means we don't need to bubble subtractive options up to bootstrap via a chain of Cargo features that aren't really meant to support disabling things. I'm sketching this out for future reference since it seems likely that the need comes back up eventually. --- library/compiler-builtins/ci/bench-icount.sh | 4 ++-- library/compiler-builtins/ci/bench-walltime.sh | 2 +- library/compiler-builtins/ci/run-extensive.sh | 10 +++++++++- library/compiler-builtins/ci/run.sh | 13 +++++-------- .../compiler-builtins/compiler-builtins/build.rs | 3 --- library/compiler-builtins/libm-test/Cargo.toml | 4 ++-- library/compiler-builtins/libm/Cargo.toml | 9 +++------ library/compiler-builtins/libm/configure.rs | 11 +---------- library/compiler-builtins/libm/src/math/arch/mod.rs | 4 ++-- .../libm/src/math/support/macros.rs | 6 +++--- 10 files changed, 28 insertions(+), 38 deletions(-) diff --git a/library/compiler-builtins/ci/bench-icount.sh b/library/compiler-builtins/ci/bench-icount.sh index 17b6997602dab..b1d0289e670ec 100755 --- a/library/compiler-builtins/ci/bench-icount.sh +++ b/library/compiler-builtins/ci/bench-icount.sh @@ -34,7 +34,7 @@ function run_icount_benchmarks() { "--target" "$target" "--bench" "*icount*" "--no-default-features" - "--features" "unstable,unstable-float,icount" + "--features" "unstable unstable-float icount" # Enable unmangled-names so our compiler-builtins gets used for # intrinsics. This makes performance impacts of c-b changes show up # in libm benchmarks and gives us a better idea of what will happen @@ -78,7 +78,7 @@ function run_icount_benchmarks() { } # Run once with softfloats, once with arch instructions enabled -run_icount_benchmarks --features force-soft-floats -- --save-baseline=softfloat +run_icount_benchmarks -- --save-baseline=softfloat run_icount_benchmarks --features arch -- --save-baseline=hardfloat if [ "$failed" != "0" ]; then diff --git a/library/compiler-builtins/ci/bench-walltime.sh b/library/compiler-builtins/ci/bench-walltime.sh index 0393d02dfc452..5d564c97beb35 100755 --- a/library/compiler-builtins/ci/bench-walltime.sh +++ b/library/compiler-builtins/ci/bench-walltime.sh @@ -6,4 +6,4 @@ export LIBM_SEED=benchesbenchesbenchesbencheswoo! cargo bench --package libm-test \ --no-default-features \ - --features walltime,short-benchmarks,build-musl,libm/force-soft-floats + --features walltime,short-benchmarks,build-musl diff --git a/library/compiler-builtins/ci/run-extensive.sh b/library/compiler-builtins/ci/run-extensive.sh index 4ba41a026fab6..9bdf8bcfbadcc 100755 --- a/library/compiler-builtins/ci/run-extensive.sh +++ b/library/compiler-builtins/ci/run-extensive.sh @@ -14,7 +14,15 @@ set -x test_cmd=( cargo test --package libm-test - --features "build-mpfr,libm/unstable,libm/force-soft-floats" + --no-default-features + # Don't enable `arch` for extensive tests. Usually anything in asm is + # only a single instruction or a small sequence, and we rely on the + # vendors to test that for us. + # + # libm/unstable enables libm/unstable-intrinsics, which means we usually + # get the single-instruction ops anyway when we aren't specifically + # testing for them. + --features "libm-test/build-mpfr libm-test/unstable-float libm/unstable" --profile release-checked ) diff --git a/library/compiler-builtins/ci/run.sh b/library/compiler-builtins/ci/run.sh index 021bc6809e43f..e66924b5a9490 100755 --- a/library/compiler-builtins/ci/run.sh +++ b/library/compiler-builtins/ci/run.sh @@ -128,9 +128,6 @@ mflags=() # We enumerate features manually. mflags+=(--no-default-features) -# Enable arch-specific routines when available. -mflags+=(--features arch) - # Always enable `unstable-float` since it expands available API but does not # change any implementations. mflags+=(--features unstable-float) @@ -198,15 +195,15 @@ else cmd+=(--exclude util --exclude libm-macros) # Test once with intrinsics enabled - "${cmd[@]}" --features unstable-intrinsics - "${cmd[@]}" --features unstable-intrinsics --benches + "${cmd[@]}" --features arch,unstable-intrinsics + "${cmd[@]}" --features arch,unstable-intrinsics --benches # Test the same in release mode, which also increases coverage. Also ensure # the soft float routines are checked. "${cmd[@]}" "$profile_flag" release-checked - "${cmd[@]}" "$profile_flag" release-checked --features force-soft-floats - "${cmd[@]}" "$profile_flag" release-checked --features unstable-intrinsics - "${cmd[@]}" "$profile_flag" release-checked --features unstable-intrinsics --benches + "${cmd[@]}" "$profile_flag" release-checked --features arch + "${cmd[@]}" "$profile_flag" release-checked --features arch,unstable-intrinsics + "${cmd[@]}" "$profile_flag" release-checked --features arch,unstable-intrinsics --benches # Ensure that the routines do not panic. # diff --git a/library/compiler-builtins/compiler-builtins/build.rs b/library/compiler-builtins/compiler-builtins/build.rs index bdbc766de8472..b845b538e4f86 100644 --- a/library/compiler-builtins/compiler-builtins/build.rs +++ b/library/compiler-builtins/compiler-builtins/build.rs @@ -89,9 +89,6 @@ fn configure_libm(target: &Target) { // Always use intrinsics set_cfg("intrinsics_enabled", true); - // The arch module may contain assembly. - set_cfg("arch_enabled", cfg!(feature = "arch")); - let opt = !matches!(target.opt_level.as_str(), "0" | "1"); set_cfg("optimizations_enabled", opt); diff --git a/library/compiler-builtins/libm-test/Cargo.toml b/library/compiler-builtins/libm-test/Cargo.toml index 9314c26831eba..271c8a599d81b 100644 --- a/library/compiler-builtins/libm-test/Cargo.toml +++ b/library/compiler-builtins/libm-test/Cargo.toml @@ -12,7 +12,7 @@ compiler_builtins = { workspace = true, default-features = false, features = ["u # This is not directly used but is required so we can enable `gmp-mpfr-sys/force-cross`. gmp-mpfr-sys = { workspace = true, optional = true } indicatif.workspace = true -libm = { workspace = true, default-features = true, features = ["unstable-public-internals"] } +libm = { workspace = true, default-features = false, features = ["unstable-public-internals"] } libm-macros.workspace = true musl-math-sys = { workspace = true, optional = true } paste.workspace = true @@ -80,5 +80,5 @@ harness = false [lints.rust] # Values from the chared config.rs used by `libm` but not the test crate unexpected_cfgs = { level = "warn", check-cfg = [ - 'cfg(feature, values("arch", "force-soft-floats", "unstable-intrinsics"))', + 'cfg(feature, values("arch", "unstable-intrinsics"))', ] } diff --git a/library/compiler-builtins/libm/Cargo.toml b/library/compiler-builtins/libm/Cargo.toml index c5d565736bc3b..98091b8255c92 100644 --- a/library/compiler-builtins/libm/Cargo.toml +++ b/library/compiler-builtins/libm/Cargo.toml @@ -38,12 +38,9 @@ unstable-public-internals = [] # Enable the nightly-only `f16` and `f128`. unstable-float = [] -# Used to prevent using any intrinsics or arch-specific code. -# -# HACK: this is a negative feature which is generally a bad idea in Cargo, but -# we need it to be able to forbid other features when this crate is used in -# Rust dependencies. Setting this overrides all features that may enable -# hard float operations. +# DEPRECATED: This feature is kept around for compatibility reasons but +# does not do anything. +# FIXME(1.0): remove this feature. force-soft-floats = [] [lints.rust] diff --git a/library/compiler-builtins/libm/configure.rs b/library/compiler-builtins/libm/configure.rs index d42faa9794925..618a994de0da9 100644 --- a/library/compiler-builtins/libm/configure.rs +++ b/library/compiler-builtins/libm/configure.rs @@ -76,7 +76,6 @@ impl Config { #[allow(dead_code)] pub fn emit_libm_config(cfg: &Config) { emit_intrinsics_cfg(); - emit_arch_cfg(); emit_optimization_cfg(cfg); emit_cfg_shorthands(cfg); emit_cfg_env(cfg); @@ -97,18 +96,10 @@ pub fn emit_test_config(cfg: &Config) { fn emit_intrinsics_cfg() { // Disabled by default; `unstable-intrinsics` enables again; `force-soft-floats` overrides // to disable. - let intrinsics = cfg!(feature = "unstable-intrinsics") && !cfg!(feature = "force-soft-floats"); + let intrinsics = cfg!(feature = "unstable-intrinsics") && cfg!(feature = "arch"); set_cfg("intrinsics_enabled", intrinsics); } -/// Simplify the feature logic for enabling arch-specific features so code only needs to use -/// `cfg(arch_enabled)`. -fn emit_arch_cfg() { - // Enabled by default via the "arch" feature, `force-soft-floats` overrides to disable. - let arch = cfg!(feature = "arch") && !cfg!(feature = "force-soft-floats"); - set_cfg("arch_enabled", arch); -} - /// Some tests are extremely slow. Emit a config option based on optimization level. fn emit_optimization_cfg(cfg: &Config) { let opt = !matches!(cfg.opt_level.as_str(), "0" | "1"); diff --git a/library/compiler-builtins/libm/src/math/arch/mod.rs b/library/compiler-builtins/libm/src/math/arch/mod.rs index 6b86cce3497d5..bcca0ff8073cf 100644 --- a/library/compiler-builtins/libm/src/math/arch/mod.rs +++ b/library/compiler-builtins/libm/src/math/arch/mod.rs @@ -7,7 +7,7 @@ // Most implementations should be defined here, to ensure they are not made available when // soft floats are required. -#[cfg(arch_enabled)] +#[cfg(feature = "arch")] cfg_if! { if #[cfg(all(target_arch = "wasm32", intrinsics_enabled))] { mod wasm32; @@ -41,7 +41,7 @@ cfg_if! { } // There are certain architecture-specific implementations that are needed for correctness -// even with `force-soft-float`. These are configured here. +// even with `arch` disabled. These are configured here. cfg_if! { if #[cfg(x86_no_sse2)] { mod i586; diff --git a/library/compiler-builtins/libm/src/math/support/macros.rs b/library/compiler-builtins/libm/src/math/support/macros.rs index 0b6cdfab66e26..fa4167d656686 100644 --- a/library/compiler-builtins/libm/src/math/support/macros.rs +++ b/library/compiler-builtins/libm/src/math/support/macros.rs @@ -46,7 +46,7 @@ macro_rules! cfg_if { /// These live in the `math::arch::some_target_arch` module. /// /// Specify a `use_arch_required` meta field if something architecture-specific must be used -/// regardless of feature configuration (`force-soft-floats`). +/// regardless of feature configuration (`arch`). /// /// The passed meta options do not need to account for the `arch` target feature. macro_rules! select_implementation { @@ -71,8 +71,8 @@ macro_rules! select_implementation { } } - // By default, never use arch-specific implementations if we have force-soft-floats - #[cfg(arch_enabled)] + // By default, never use arch-specific implementations if `arch` is disabled. + #[cfg(feature = "arch")] select_implementation! { @cfg $($use_arch)?; // Wrap in `if true` to avoid unused warnings From 719d7f9e17c88ddd9c26b42c8151fd3757fb07ec Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Wed, 1 Apr 2026 19:15:01 -0400 Subject: [PATCH 089/183] bench: Rename the benchmark baselines These no longer test just softfloat and hardfloat, but also the fallback implementations in `mem` compared to those that make use of assembly. Change the baseline names to be more accurate of the difference. --- library/compiler-builtins/ci/bench-icount.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/library/compiler-builtins/ci/bench-icount.sh b/library/compiler-builtins/ci/bench-icount.sh index b1d0289e670ec..cd36303ca316a 100755 --- a/library/compiler-builtins/ci/bench-icount.sh +++ b/library/compiler-builtins/ci/bench-icount.sh @@ -78,8 +78,8 @@ function run_icount_benchmarks() { } # Run once with softfloats, once with arch instructions enabled -run_icount_benchmarks -- --save-baseline=softfloat -run_icount_benchmarks --features arch -- --save-baseline=hardfloat +run_icount_benchmarks -- --save-baseline=arch_disabled +run_icount_benchmarks --features arch -- --save-baseline=arch_enabled if [ "$failed" != "0" ]; then echo "One or more benchmarks failed" From 312b9946c7a1a71089522d0bdc966ab9be42864d Mon Sep 17 00:00:00 2001 From: Brian Cain Date: Wed, 1 Apr 2026 22:27:13 -0700 Subject: [PATCH 090/183] c-b: Add hexagon common entry/exit ABI routines and memcpy_dwloop Add callee-saved register save/restore routines for three hexagon ABIs (abi1, abi2, legacy) and a double-word loop memcpy implementation. Also add a FALLTHROUGH_TAIL_CALL macro to func_macro.s for chaining function entry points without branches. Refer to https://github.com/llvm/llvm-project/tree/c1fd7d7a1f573477d86a716bacda01ed1d8c7a43/compiler-rt/lib/builtins/hexagon for corresponding clang-rt hexagon builtin source. --- .../compiler-builtins/src/hexagon.rs | 15 ++ .../src/hexagon/common_entry_exit_abi1.s | 42 ++++ .../src/hexagon/common_entry_exit_abi2.s | 237 ++++++++++++++++++ .../src/hexagon/common_entry_exit_legacy.s | 92 +++++++ .../src/hexagon/func_macro.s | 8 + .../src/hexagon/memcpy_likely_aligned.s | 29 +++ 6 files changed, 423 insertions(+) create mode 100644 library/compiler-builtins/compiler-builtins/src/hexagon/common_entry_exit_abi1.s create mode 100644 library/compiler-builtins/compiler-builtins/src/hexagon/common_entry_exit_abi2.s create mode 100644 library/compiler-builtins/compiler-builtins/src/hexagon/common_entry_exit_legacy.s diff --git a/library/compiler-builtins/compiler-builtins/src/hexagon.rs b/library/compiler-builtins/compiler-builtins/src/hexagon.rs index a5c7b4dfdda91..170c786bbf517 100644 --- a/library/compiler-builtins/compiler-builtins/src/hexagon.rs +++ b/library/compiler-builtins/compiler-builtins/src/hexagon.rs @@ -2,6 +2,21 @@ use core::arch::global_asm; global_asm!(include_str!("hexagon/func_macro.s"), options(raw)); +global_asm!( + include_str!("hexagon/common_entry_exit_abi1.s"), + options(raw) +); + +global_asm!( + include_str!("hexagon/common_entry_exit_abi2.s"), + options(raw) +); + +global_asm!( + include_str!("hexagon/common_entry_exit_legacy.s"), + options(raw) +); + global_asm!(include_str!("hexagon/dfaddsub.s"), options(raw)); global_asm!(include_str!("hexagon/dfdiv.s"), options(raw)); diff --git a/library/compiler-builtins/compiler-builtins/src/hexagon/common_entry_exit_abi1.s b/library/compiler-builtins/compiler-builtins/src/hexagon/common_entry_exit_abi1.s new file mode 100644 index 0000000000000..61425abaad5ae --- /dev/null +++ b/library/compiler-builtins/compiler-builtins/src/hexagon/common_entry_exit_abi1.s @@ -0,0 +1,42 @@ + +FUNCTION_BEGIN __save_r24_through_r27 + memd(fp+#-16) = r27:26 +FALLTHROUGH_TAIL_CALL __save_r24_through_r27 __save_r24_through_r25 + { + memd(fp+#-8) = r25:24 + jumpr lr + } +FUNCTION_END __save_r24_through_r25 + + +FUNCTION_BEGIN __restore_r24_through_r27_and_deallocframe_before_tailcall + r27:26 = memd(fp+#-16) +FALLTHROUGH_TAIL_CALL __restore_r24_through_r27_and_deallocframe_before_tailcall __restore_r24_through_r25_and_deallocframe_before_tailcall + { + r25:24 = memd(fp+#-8) + deallocframe + jumpr lr + } +FUNCTION_END __restore_r24_through_r25_and_deallocframe_before_tailcall + + +FUNCTION_BEGIN __restore_r24_through_r27_and_deallocframe + { + lr = memw(fp+#4) + r27:26 = memd(fp+#-16) + } + { + r25:24 = memd(fp+#-8) + deallocframe + jumpr lr + } +FUNCTION_END __restore_r24_through_r27_and_deallocframe + + +FUNCTION_BEGIN __restore_r24_through_r25_and_deallocframe + { + r25:24 = memd(fp+#-8) + deallocframe + } + jumpr lr +FUNCTION_END __restore_r24_through_r25_and_deallocframe diff --git a/library/compiler-builtins/compiler-builtins/src/hexagon/common_entry_exit_abi2.s b/library/compiler-builtins/compiler-builtins/src/hexagon/common_entry_exit_abi2.s new file mode 100644 index 0000000000000..8734310fc3758 --- /dev/null +++ b/library/compiler-builtins/compiler-builtins/src/hexagon/common_entry_exit_abi2.s @@ -0,0 +1,237 @@ + + .macro ABI2_FUNCTION_BEGIN name + .p2align 2 + .section .text.\name,"ax",@progbits + .globl \name + .type \name, @function +\name: + .endm + + .macro ABI2_FUNCTION_END name + .size \name, . - \name + .endm + + +ABI2_FUNCTION_BEGIN __save_r16_through_r27 + { + memd(fp+#-48) = r27:26 + memd(fp+#-40) = r25:24 + } + { + memd(fp+#-32) = r23:22 + memd(fp+#-24) = r21:20 + } + { + memd(fp+#-16) = r19:18 + memd(fp+#-8) = r17:16 + jumpr lr + } +ABI2_FUNCTION_END __save_r16_through_r27 + +ABI2_FUNCTION_BEGIN __save_r16_through_r25 + { + memd(fp+#-40) = r25:24 + memd(fp+#-32) = r23:22 + } + { + memd(fp+#-24) = r21:20 + memd(fp+#-16) = r19:18 + } + { + memd(fp+#-8) = r17:16 + jumpr lr + } +ABI2_FUNCTION_END __save_r16_through_r25 + +ABI2_FUNCTION_BEGIN __save_r16_through_r23 + { + memd(fp+#-32) = r23:22 + memd(fp+#-24) = r21:20 + } + { + memd(fp+#-16) = r19:18 + memd(fp+#-8) = r17:16 + jumpr lr + } +ABI2_FUNCTION_END __save_r16_through_r23 + +ABI2_FUNCTION_BEGIN __save_r16_through_r21 + { + memd(fp+#-24) = r21:20 + memd(fp+#-16) = r19:18 + } + { + memd(fp+#-8) = r17:16 + jumpr lr + } +ABI2_FUNCTION_END __save_r16_through_r21 + +ABI2_FUNCTION_BEGIN __save_r16_through_r19 + { + memd(fp+#-16) = r19:18 + memd(fp+#-8) = r17:16 + jumpr lr + } +ABI2_FUNCTION_END __save_r16_through_r19 + +ABI2_FUNCTION_BEGIN __save_r16_through_r17 + { + memd(fp+#-8) = r17:16 + jumpr lr + } +ABI2_FUNCTION_END __save_r16_through_r17 + + +ABI2_FUNCTION_BEGIN __restore_r16_through_r27_and_deallocframe_before_tailcall + r27:26 = memd(fp+#-48) + { + r25:24 = memd(fp+#-40) + r23:22 = memd(fp+#-32) + } + { + r21:20 = memd(fp+#-24) + r19:18 = memd(fp+#-16) + } + { + r17:16 = memd(fp+#-8) + deallocframe + jumpr lr + } +ABI2_FUNCTION_END __restore_r16_through_r27_and_deallocframe_before_tailcall + +ABI2_FUNCTION_BEGIN __restore_r16_through_r25_and_deallocframe_before_tailcall + { + r25:24 = memd(fp+#-40) + r23:22 = memd(fp+#-32) + } + { + r21:20 = memd(fp+#-24) + r19:18 = memd(fp+#-16) + } + { + r17:16 = memd(fp+#-8) + deallocframe + jumpr lr + } +ABI2_FUNCTION_END __restore_r16_through_r25_and_deallocframe_before_tailcall + +ABI2_FUNCTION_BEGIN __restore_r16_through_r23_and_deallocframe_before_tailcall + { + r23:22 = memd(fp+#-32) + r21:20 = memd(fp+#-24) + } + r19:18 = memd(fp+#-16) + { + r17:16 = memd(fp+#-8) + deallocframe + jumpr lr + } +ABI2_FUNCTION_END __restore_r16_through_r23_and_deallocframe_before_tailcall + + +ABI2_FUNCTION_BEGIN __restore_r16_through_r21_and_deallocframe_before_tailcall + { + r21:20 = memd(fp+#-24) + r19:18 = memd(fp+#-16) + } + { + r17:16 = memd(fp+#-8) + deallocframe + jumpr lr + } +ABI2_FUNCTION_END __restore_r16_through_r21_and_deallocframe_before_tailcall + +ABI2_FUNCTION_BEGIN __restore_r16_through_r19_and_deallocframe_before_tailcall + r19:18 = memd(fp+#-16) + { + r17:16 = memd(fp+#-8) + deallocframe + jumpr lr + } +ABI2_FUNCTION_END __restore_r16_through_r19_and_deallocframe_before_tailcall + +ABI2_FUNCTION_BEGIN __restore_r16_through_r17_and_deallocframe_before_tailcall + { + r17:16 = memd(fp+#-8) + deallocframe + jumpr lr + } +ABI2_FUNCTION_END __restore_r16_through_r17_and_deallocframe_before_tailcall + + +ABI2_FUNCTION_BEGIN __restore_r16_through_r27_and_deallocframe + r27:26 = memd(fp+#-48) + { + r25:24 = memd(fp+#-40) + r23:22 = memd(fp+#-32) + } + { + r21:20 = memd(fp+#-24) + r19:18 = memd(fp+#-16) + } + { + r17:16 = memd(fp+#-8) + dealloc_return + } +ABI2_FUNCTION_END __restore_r16_through_r27_and_deallocframe + +ABI2_FUNCTION_BEGIN __restore_r16_through_r25_and_deallocframe + { + r25:24 = memd(fp+#-40) + r23:22 = memd(fp+#-32) + } + { + r21:20 = memd(fp+#-24) + r19:18 = memd(fp+#-16) + } + { + r17:16 = memd(fp+#-8) + dealloc_return + } +ABI2_FUNCTION_END __restore_r16_through_r25_and_deallocframe + +ABI2_FUNCTION_BEGIN __restore_r16_through_r23_and_deallocframe + { + r23:22 = memd(fp+#-32) + } + { + r21:20 = memd(fp+#-24) + r19:18 = memd(fp+#-16) + } + { + r17:16 = memd(fp+#-8) + dealloc_return + } +ABI2_FUNCTION_END __restore_r16_through_r23_and_deallocframe + +ABI2_FUNCTION_BEGIN __restore_r16_through_r21_and_deallocframe + { + r21:20 = memd(fp+#-24) + r19:18 = memd(fp+#-16) + } + { + r17:16 = memd(fp+#-8) + dealloc_return + } +ABI2_FUNCTION_END __restore_r16_through_r21_and_deallocframe + +ABI2_FUNCTION_BEGIN __restore_r16_through_r19_and_deallocframe + { + r19:18 = memd(fp+#-16) + r17:16 = memd(fp+#-8) + } + { + dealloc_return + } +ABI2_FUNCTION_END __restore_r16_through_r19_and_deallocframe + +ABI2_FUNCTION_BEGIN __restore_r16_through_r17_and_deallocframe + { + r17:16 = memd(fp+#-8) + dealloc_return + } +ABI2_FUNCTION_END __restore_r16_through_r17_and_deallocframe + +ABI2_FUNCTION_BEGIN __deallocframe + dealloc_return +ABI2_FUNCTION_END __deallocframe diff --git a/library/compiler-builtins/compiler-builtins/src/hexagon/common_entry_exit_legacy.s b/library/compiler-builtins/compiler-builtins/src/hexagon/common_entry_exit_legacy.s new file mode 100644 index 0000000000000..4c539ea91f4af --- /dev/null +++ b/library/compiler-builtins/compiler-builtins/src/hexagon/common_entry_exit_legacy.s @@ -0,0 +1,92 @@ + +FUNCTION_BEGIN __save_r27_through_r16 + memd(fp+#-48) = r17:16 +FALLTHROUGH_TAIL_CALL __save_r27_through_r16 __save_r27_through_r18 + memd(fp+#-40) = r19:18 +FALLTHROUGH_TAIL_CALL __save_r27_through_r18 __save_r27_through_r20 + memd(fp+#-32) = r21:20 +FALLTHROUGH_TAIL_CALL __save_r27_through_r20 __save_r27_through_r22 + memd(fp+#-24) = r23:22 +FALLTHROUGH_TAIL_CALL __save_r27_through_r22 __save_r27_through_r24 + memd(fp+#-16) = r25:24 + { + memd(fp+#-8) = r27:26 + jumpr lr + } +FUNCTION_END __save_r27_through_r24 + + +FUNCTION_BEGIN __restore_r27_through_r20_and_deallocframe_before_sibcall + { + r21:20 = memd(fp+#-32) + r23:22 = memd(fp+#-24) + } +FALLTHROUGH_TAIL_CALL __restore_r27_through_r20_and_deallocframe_before_sibcall __restore_r27_through_r24_and_deallocframe_before_sibcall + { + r25:24 = memd(fp+#-16) + jump __restore_r27_through_r26_and_deallocframe_before_sibcall + } +FUNCTION_END __restore_r27_through_r24_and_deallocframe_before_sibcall + + +FUNCTION_BEGIN __restore_r27_through_r16_and_deallocframe_before_sibcall + r17:16 = memd(fp+#-48) +FALLTHROUGH_TAIL_CALL __restore_r27_through_r16_and_deallocframe_before_sibcall __restore_r27_through_r18_and_deallocframe_before_sibcall + { + r19:18 = memd(fp+#-40) + r21:20 = memd(fp+#-32) + } +FALLTHROUGH_TAIL_CALL __restore_r27_through_r18_and_deallocframe_before_sibcall __restore_r27_through_r22_and_deallocframe_before_sibcall + { + r23:22 = memd(fp+#-24) + r25:24 = memd(fp+#-16) + } +FALLTHROUGH_TAIL_CALL __restore_r27_through_r22_and_deallocframe_before_sibcall __restore_r27_through_r26_and_deallocframe_before_sibcall + { + r27:26 = memd(fp+#-8) + deallocframe + jumpr lr + } +FUNCTION_END __restore_r27_through_r26_and_deallocframe_before_sibcall + + +FUNCTION_BEGIN __restore_r27_through_r16_and_deallocframe + { + r17:16 = memd(fp+#-48) + r19:18 = memd(fp+#-40) + } +FALLTHROUGH_TAIL_CALL __restore_r27_through_r16_and_deallocframe __restore_r27_through_r20_and_deallocframe + { + r21:20 = memd(fp+#-32) + r23:22 = memd(fp+#-24) + } +FALLTHROUGH_TAIL_CALL __restore_r27_through_r20_and_deallocframe __restore_r27_through_r24_and_deallocframe + { + lr = memw(fp+#4) + r25:24 = memd(fp+#-16) + } + { + r27:26 = memd(fp+#-8) + deallocframe + jumpr lr + } +FUNCTION_END __restore_r27_through_r24_and_deallocframe + + +FUNCTION_BEGIN __restore_r27_through_r18_and_deallocframe + { + r19:18 = memd(fp+#-40) + r21:20 = memd(fp+#-32) + } +FALLTHROUGH_TAIL_CALL __restore_r27_through_r18_and_deallocframe __restore_r27_through_r22_and_deallocframe + { + r23:22 = memd(fp+#-24) + r25:24 = memd(fp+#-16) + } +FALLTHROUGH_TAIL_CALL __restore_r27_through_r22_and_deallocframe __restore_r27_through_r26_and_deallocframe + { + r27:26 = memd(fp+#-8) + deallocframe + } + jumpr lr +FUNCTION_END __restore_r27_through_r26_and_deallocframe diff --git a/library/compiler-builtins/compiler-builtins/src/hexagon/func_macro.s b/library/compiler-builtins/compiler-builtins/src/hexagon/func_macro.s index 9a1e11aebcb50..f5514cb7f057b 100644 --- a/library/compiler-builtins/compiler-builtins/src/hexagon/func_macro.s +++ b/library/compiler-builtins/compiler-builtins/src/hexagon/func_macro.s @@ -10,3 +10,11 @@ .size \name, . - \name .endm + .macro FALLTHROUGH_TAIL_CALL name0 name1 + .size \name0, . - \name0 + .globl \name1 + .type \name1, @function + .falign +\name1: + .endm + diff --git a/library/compiler-builtins/compiler-builtins/src/hexagon/memcpy_likely_aligned.s b/library/compiler-builtins/compiler-builtins/src/hexagon/memcpy_likely_aligned.s index 7e9b62f6a791c..416675833192e 100644 --- a/library/compiler-builtins/compiler-builtins/src/hexagon/memcpy_likely_aligned.s +++ b/library/compiler-builtins/compiler-builtins/src/hexagon/memcpy_likely_aligned.s @@ -31,6 +31,35 @@ FUNCTION_BEGIN __hexagon_memcpy_likely_aligned_min32bytes_mult8bytes } FUNCTION_END __hexagon_memcpy_likely_aligned_min32bytes_mult8bytes +FUNCTION_BEGIN __hexagon_memcpy_dwloop + { + r5:4 = memd(r1) + r3 = #-3 + } + { + memd(r0++#8) = r5:4 + r5:4 = memd(r1+#8) + r3 += lsr(r2,#3) + } + { + memd(r0++#8) = r5:4 + r5:4 = memd(r1+#16) + r1 = add(r1,#24) + loop0(1f,r3) + } + .falign +1: + { + memd(r0++#8) = r5:4 + r5:4 = memd(r1++#8) + }:endloop0 + { + memd(r0) = r5:4 + r0 -= add(r2,#-8) + jumpr r31 + } +FUNCTION_END __hexagon_memcpy_dwloop + .Lmemcpy_call: jump memcpy@PLT From 6bbf64e1dd5ffa08facdd3a0d33178faebca1825 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Sun, 29 Mar 2026 16:44:27 -0500 Subject: [PATCH 091/183] roundeven: Use an assembly implementation on i586 Add an assembly implementation for roundeven which also works for `rint`, similar to the existing `ceil` and `floor` implementations. This resolves cases where values close to the *.5 boundary would round the incorrect direction, such as -519629176421.49976 (tested in `case_list`). --- .../etc/function-definitions.json | 1 + .../libm-test/src/precision.rs | 9 ---- .../libm/src/math/arch/i586/mod.rs | 2 +- .../libm/src/math/arch/i586/rounding.rs | 50 +++++++++++++++++++ .../libm/src/math/arch/mod.rs | 1 + .../compiler-builtins/libm/src/math/rint.rs | 1 + 6 files changed, 54 insertions(+), 10 deletions(-) diff --git a/library/compiler-builtins/etc/function-definitions.json b/library/compiler-builtins/etc/function-definitions.json index 39f7897047798..38d609da3fcfa 100644 --- a/library/compiler-builtins/etc/function-definitions.json +++ b/library/compiler-builtins/etc/function-definitions.json @@ -824,6 +824,7 @@ "rint": { "sources": [ "libm/src/math/arch/aarch64/rounding.rs", + "libm/src/math/arch/i586/rounding.rs", "libm/src/math/arch/wasm32/rounding.rs", "libm/src/math/generic/rint.rs", "libm/src/math/rint.rs" diff --git a/library/compiler-builtins/libm-test/src/precision.rs b/library/compiler-builtins/libm-test/src/precision.rs index bc28d970e7642..2034e89c71e46 100644 --- a/library/compiler-builtins/libm-test/src/precision.rs +++ b/library/compiler-builtins/libm-test/src/precision.rs @@ -297,15 +297,6 @@ impl MaybeOverride<(f32,)> for SpecialCase { impl MaybeOverride<(f64,)> for SpecialCase { fn check_float(input: (f64,), actual: F, expected: F, ctx: &CheckCtx) -> CheckAction { - if cfg!(x86_no_sse2) - && (ctx.base_name == BaseName::Rint || ctx.base_name == BaseName::Roundeven) - && (expected - actual).abs() <= F::ONE - && (expected - actual).abs() > F::ZERO - { - // Our rounding mode is incorrect. - return XFAIL("i586 rint rounding mode"); - } - if ctx.base_name == BaseName::J0 && input.0 < -1e300 { // Errors get huge close to -inf return XFAIL_NOCHECK; diff --git a/library/compiler-builtins/libm/src/math/arch/i586/mod.rs b/library/compiler-builtins/libm/src/math/arch/i586/mod.rs index fa8b798757640..f80be49fc4b3f 100644 --- a/library/compiler-builtins/libm/src/math/arch/i586/mod.rs +++ b/library/compiler-builtins/libm/src/math/arch/i586/mod.rs @@ -11,4 +11,4 @@ mod exp_all; mod rounding; pub use exp_all::{x87_exp, x87_exp2, x87_exp2f, x87_exp10, x87_exp10f, x87_expf}; -pub use rounding::{ceil, floor}; +pub use rounding::{ceil, floor, rint}; diff --git a/library/compiler-builtins/libm/src/math/arch/i586/rounding.rs b/library/compiler-builtins/libm/src/math/arch/i586/rounding.rs index 3981e3d109ff8..45bf0adafd304 100644 --- a/library/compiler-builtins/libm/src/math/arch/i586/rounding.rs +++ b/library/compiler-builtins/libm/src/math/arch/i586/rounding.rs @@ -51,3 +51,53 @@ pub fn floor(mut x: f64) -> f64 { } x } + +/// Note that this respects rounding mode. Because it is UB to have a non-default rounding +/// mode in Rust, this acts as roundeven. +pub fn rint(mut x: f64) -> f64 { + unsafe { + core::arch::asm!( + "fld qword ptr [{x}]", + "frndint", + "fstp qword ptr [{x}]", + x = in(reg) &mut x, + // All the x87 FPU stack is used, all registers must be clobbered + out("st(0)") _, out("st(1)") _, + out("st(2)") _, out("st(3)") _, + out("st(4)") _, out("st(5)") _, + out("st(6)") _, out("st(7)") _, + options(nostack), + ); + } + x +} + +/* FIXME(msrv): after 1.82, the below can be used to compute control words using `asm_const`: + +#[derive(Clone, Copy, Debug, PartialEq)] +enum Precision { + Single, + Double, + Extended, +} + +/// See: Intel® 64 and IA-32 Architectures Software Developer's Manual Volume 1: +/// Basic Architecture, section 8.1.5 x87 FPU Control Word. +const fn make_fpcw(round: Round, prec: Precision) -> u16 { + let exceptions = 0b111111; // Disable all 6 exceptions + let misc = 0b1000000; // reserved field usually set by default + let pc = match prec { + Precision::Single => 0b00, + Precision::Double => 0b10, + Precision::Extended => 0b11, + }; + let rc = match round { + Round::Nearest => 0b00, + Round::Negative => 0b01, + Round::Positive => 0b10, + Round::Zero => 0b11, + }; + (rc << 10) | (pc << 8) | misc | exceptions +} + +*/ diff --git a/library/compiler-builtins/libm/src/math/arch/mod.rs b/library/compiler-builtins/libm/src/math/arch/mod.rs index bcca0ff8073cf..1bed464cfa7d6 100644 --- a/library/compiler-builtins/libm/src/math/arch/mod.rs +++ b/library/compiler-builtins/libm/src/math/arch/mod.rs @@ -48,6 +48,7 @@ cfg_if! { pub use i586::{ ceil, floor, + rint, x87_exp, x87_exp10, x87_exp10f, diff --git a/library/compiler-builtins/libm/src/math/rint.rs b/library/compiler-builtins/libm/src/math/rint.rs index 0cb0e2d3637d1..75c46acc0e856 100644 --- a/library/compiler-builtins/libm/src/math/rint.rs +++ b/library/compiler-builtins/libm/src/math/rint.rs @@ -37,6 +37,7 @@ pub fn rint(x: f64) -> f64 { all(target_arch = "aarch64", target_feature = "neon"), all(target_arch = "wasm32", intrinsics_enabled), ), + use_arch_required: x86_no_sse2, args: x, } From 73cb91db4e3f25517927d684fb01a94e11ea9495 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Tue, 7 Apr 2026 03:12:11 -0400 Subject: [PATCH 092/183] test: Give helper functions in `spaced` more accurate names --- .../libm-test/src/generate/spaced.rs | 44 ++++++++++--------- 1 file changed, 23 insertions(+), 21 deletions(-) diff --git a/library/compiler-builtins/libm-test/src/generate/spaced.rs b/library/compiler-builtins/libm-test/src/generate/spaced.rs index a825fe4c323b2..b6bc4e9ac5d5e 100644 --- a/library/compiler-builtins/libm-test/src/generate/spaced.rs +++ b/library/compiler-builtins/libm-test/src/generate/spaced.rs @@ -66,14 +66,14 @@ impl, B: Iterator> Iterator for EitherIter() -> Option +fn total_value_count() -> Option where u64: TryFrom, { - value_count_int::() + total_value_count_int::() } -fn value_count_int() -> Option +fn total_value_count_int() -> Option where u64: TryFrom, { @@ -83,7 +83,7 @@ where } /// Returns an iterator of every possible value of type `F`. -fn all_values() -> impl Iterator +fn exhaustive_float() -> impl Iterator where RangeInclusive: Iterator, { @@ -99,9 +99,9 @@ macro_rules! impl_spaced_input { fn get_cases(ctx: &CheckCtx) -> (impl Iterator, u64) { let max_steps0 = iteration_count(ctx, 0); // `f16` and `f32` can have exhaustive tests. - match value_count::>() { + match total_value_count::>() { Some(steps0) if steps0 <= max_steps0 => { - let iter0 = all_values(); + let iter0 = exhaustive_float(); let iter0 = iter0.map(|v| (v,)); (EitherIter::A(iter0), steps0) } @@ -122,10 +122,11 @@ macro_rules! impl_spaced_input { let max_steps0 = iteration_count(ctx, 0); let max_steps1 = iteration_count(ctx, 1); // `f16` can have exhaustive tests. - match value_count::>() { + match total_value_count::>() { Some(count) if count <= max_steps0 && count <= max_steps1 => { - let iter = all_values() - .flat_map(|first| all_values().map(move |second| (first, second))); + let iter = exhaustive_float().flat_map(|first| { + exhaustive_float().map(move |second| (first, second)) + }); (EitherIter::A(iter), count.checked_mul(count).unwrap()) } _ => { @@ -150,13 +151,13 @@ macro_rules! impl_spaced_input { let max_steps1 = iteration_count(ctx, 1); let max_steps2 = iteration_count(ctx, 2); // `f16` can be exhaustive tested if `LIBM_EXTENSIVE_TESTS` is incresed. - match value_count::>() { + match total_value_count::>() { Some(count) if count <= max_steps0 && count <= max_steps1 && count <= max_steps2 => { - let iter = all_values().flat_map(|first| { - all_values().flat_map(move |second| { - all_values().map(move |third| (first, second, third)) + let iter = exhaustive_float().flat_map(|first| { + exhaustive_float().flat_map(move |second| { + exhaustive_float().map(move |third| (first, second, third)) }) }); (EitherIter::A(iter), count.checked_pow(3).unwrap()) @@ -191,11 +192,12 @@ macro_rules! impl_spaced_input { let range0 = int_range(ctx, 0).unwrap_or(full_range()); let max_steps0 = iteration_count(ctx, 0); let max_steps1 = iteration_count(ctx, 1); - match value_count::>() { + match total_value_count::>() { Some(count1) if count1 <= max_steps1 => { let (iter0, steps0) = linear_ints(range0, max_steps0); - let iter = iter0 - .flat_map(move |first| all_values().map(move |second| (first, second))); + let iter = iter0.flat_map(move |first| { + exhaustive_float().map(move |second| (first, second)) + }); (EitherIter::A(iter), steps0.checked_mul(count1).unwrap()) } _ => { @@ -221,10 +223,10 @@ macro_rules! impl_spaced_input { let max_steps0 = iteration_count(ctx, 0); let range1 = int_range(ctx, 1).unwrap_or(full_range()); let max_steps1 = iteration_count(ctx, 1); - match value_count::>() { + match total_value_count::>() { Some(count0) if count0 <= max_steps0 => { let (iter1, steps1) = linear_ints(range1, max_steps1); - let iter = all_values().flat_map(move |first| { + let iter = exhaustive_float().flat_map(move |first| { iter1.clone().map(move |second| (first, second)) }); (EitherIter::A(iter), count0.checked_mul(steps1).unwrap()) @@ -262,7 +264,7 @@ macro_rules! impl_spaced_input_int { fn get_cases(ctx: &CheckCtx) -> (impl Iterator, u64) { let range = int_range(ctx, 0).unwrap_or(full_range()); let max_steps0 = iteration_count(ctx, 0); - match value_count_int::>() { + match total_value_count_int::>() { Some(steps0) if steps0 <= max_steps0 => { let iter0 = range.map(|v| (v,)); (EitherIter::A(iter0), steps0) @@ -285,7 +287,7 @@ macro_rules! impl_spaced_input_int { let range1 = int_range(ctx, 1).unwrap_or(full_range()); let max_steps0 = iteration_count(ctx, 0); let max_steps1 = iteration_count(ctx, 0); - match value_count_int::>() { + match total_value_count_int::>() { Some(count) if count <= max_steps0 && count < max_steps1 => { let iter = range0.flat_map(move |first| { range1.clone().map(move |second| (first, second)) @@ -317,7 +319,7 @@ macro_rules! impl_spaced_input_int { let range1 = int_range(ctx, 1).unwrap_or(full_range()); let max_steps0 = iteration_count(ctx, 0); let max_steps1 = iteration_count(ctx, 0); - match value_count_int::>() { + match total_value_count_int::>() { Some(count) if count <= max_steps0 && count < max_steps1 => { let iter = range0.flat_map(move |first| { range1.clone().map(move |second| (first, second)) From 5344da9654a59ca9d2a5ebee29f705bdf693e2a7 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Tue, 7 Apr 2026 03:16:51 -0400 Subject: [PATCH 093/183] test: Make use of `strict_mul` rather than `checked_mul(..).unwrap()` --- .../libm-test/src/generate/spaced.rs | 30 +++++++++---------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/library/compiler-builtins/libm-test/src/generate/spaced.rs b/library/compiler-builtins/libm-test/src/generate/spaced.rs index b6bc4e9ac5d5e..3474844ad7a57 100644 --- a/library/compiler-builtins/libm-test/src/generate/spaced.rs +++ b/library/compiler-builtins/libm-test/src/generate/spaced.rs @@ -127,7 +127,7 @@ macro_rules! impl_spaced_input { let iter = exhaustive_float().flat_map(|first| { exhaustive_float().map(move |second| (first, second)) }); - (EitherIter::A(iter), count.checked_mul(count).unwrap()) + (EitherIter::A(iter), count.strict_mul(count)) } _ => { let (iter0, steps0) = logspace_steps::>(ctx, 0, max_steps0); @@ -135,7 +135,7 @@ macro_rules! impl_spaced_input { let iter = iter0.flat_map(move |first| { iter1.clone().map(move |second| (first, second)) }); - let count = steps0.checked_mul(steps1).unwrap(); + let count = steps0.strict_mul(steps1); (EitherIter::B(iter), count) } } @@ -172,11 +172,7 @@ macro_rules! impl_spaced_input { .flat_map(move |(first, second)| { iter2.clone().map(move |third| (first, second, third)) }); - let count = steps0 - .checked_mul(steps1) - .unwrap() - .checked_mul(steps2) - .unwrap(); + let count = steps0.strict_mul(steps1).strict_mul(steps2); (EitherIter::B(iter), count) } @@ -198,7 +194,8 @@ macro_rules! impl_spaced_input { let iter = iter0.flat_map(move |first| { exhaustive_float().map(move |second| (first, second)) }); - (EitherIter::A(iter), steps0.checked_mul(count1).unwrap()) + let count = steps0.strict_mul(count1); + (EitherIter::A(iter), count) } _ => { let (iter0, steps0) = linear_ints(range0, max_steps0); @@ -207,7 +204,7 @@ macro_rules! impl_spaced_input { let iter = iter0.flat_map(move |first| { iter1.clone().map(move |second| (first, second)) }); - let count = steps0.checked_mul(steps1).unwrap(); + let count = steps0.strict_mul(steps1); (EitherIter::B(iter), count) } @@ -229,7 +226,8 @@ macro_rules! impl_spaced_input { let iter = exhaustive_float().flat_map(move |first| { iter1.clone().map(move |second| (first, second)) }); - (EitherIter::A(iter), count0.checked_mul(steps1).unwrap()) + let count = count0.strict_mul(steps1); + (EitherIter::A(iter), count) } _ => { let (iter0, steps0) = logspace_steps::>(ctx, 0, max_steps0); @@ -238,7 +236,7 @@ macro_rules! impl_spaced_input { let iter = iter0.flat_map(move |first| { iter1.clone().map(move |second| (first, second)) }); - let count = steps0.checked_mul(steps1).unwrap(); + let count = steps0.strict_mul(steps1); (EitherIter::B(iter), count) } @@ -292,7 +290,8 @@ macro_rules! impl_spaced_input_int { let iter = range0.flat_map(move |first| { range1.clone().map(move |second| (first, second)) }); - (EitherIter::A(iter), count.checked_mul(count).unwrap()) + let count = count.strict_mul(count); + (EitherIter::A(iter), count) } _ => { let (iter0, steps0) = linear_ints::>(range0, max_steps0); @@ -300,7 +299,7 @@ macro_rules! impl_spaced_input_int { let iter = iter0.flat_map(move |first| { iter1.clone().map(move |second| (first, second)) }); - let count = steps0.checked_mul(steps1).unwrap(); + let count = steps0.strict_mul(steps1); (EitherIter::B(iter), count) } } @@ -324,7 +323,8 @@ macro_rules! impl_spaced_input_int { let iter = range0.flat_map(move |first| { range1.clone().map(move |second| (first, second)) }); - (EitherIter::A(iter), count.checked_mul(count).unwrap()) + let count = count.strict_mul(count); + (EitherIter::A(iter), count) } _ => { let (iter0, steps0) = linear_ints::>(range0, max_steps0); @@ -332,7 +332,7 @@ macro_rules! impl_spaced_input_int { let iter = iter0.flat_map(move |first| { iter1.clone().map(move |second| (first, second)) }); - let count = steps0.checked_mul(steps1).unwrap(); + let count = steps0.strict_mul(steps1); (EitherIter::B(iter), count) } } From 5678e6187d89a4779d12d255627f1bd4f01edaab Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Tue, 7 Apr 2026 03:03:06 -0400 Subject: [PATCH 094/183] test: Use `let` chains to simplify patterns in generator macros --- .../libm-test/src/generate/spaced.rs | 295 +++++++++--------- 1 file changed, 156 insertions(+), 139 deletions(-) diff --git a/library/compiler-builtins/libm-test/src/generate/spaced.rs b/library/compiler-builtins/libm-test/src/generate/spaced.rs index 3474844ad7a57..ba04b99512729 100644 --- a/library/compiler-builtins/libm-test/src/generate/spaced.rs +++ b/library/compiler-builtins/libm-test/src/generate/spaced.rs @@ -98,19 +98,21 @@ macro_rules! impl_spaced_input { { fn get_cases(ctx: &CheckCtx) -> (impl Iterator, u64) { let max_steps0 = iteration_count(ctx, 0); - // `f16` and `f32` can have exhaustive tests. - match total_value_count::>() { - Some(steps0) if steps0 <= max_steps0 => { - let iter0 = exhaustive_float(); - let iter0 = iter0.map(|v| (v,)); - (EitherIter::A(iter0), steps0) - } - _ => { - let (iter0, steps0) = logspace_steps::>(ctx, 0, max_steps0); - let iter0 = iter0.map(|v| (v,)); - (EitherIter::B(iter0), steps0) - } + + // Unary tests: `f16` and `f32` may be exhaustive. + if let Some(steps0) = total_value_count::>() + && steps0 <= max_steps0 + { + let iter0 = exhaustive_float(); + let iter0 = iter0.map(|v| (v,)); + + return (EitherIter::A(iter0), steps0); } + + // Non-exhaustive, sweep a subset of inputs. + let (iter0, steps0) = logspace_steps::>(ctx, 0, max_steps0); + let iter0 = iter0.map(|v| (v,)); + (EitherIter::B(iter0), steps0) } } @@ -121,24 +123,29 @@ macro_rules! impl_spaced_input { fn get_cases(ctx: &CheckCtx) -> (impl Iterator, u64) { let max_steps0 = iteration_count(ctx, 0); let max_steps1 = iteration_count(ctx, 1); - // `f16` can have exhaustive tests. - match total_value_count::>() { - Some(count) if count <= max_steps0 && count <= max_steps1 => { - let iter = exhaustive_float().flat_map(|first| { - exhaustive_float().map(move |second| (first, second)) - }); - (EitherIter::A(iter), count.strict_mul(count)) - } - _ => { - let (iter0, steps0) = logspace_steps::>(ctx, 0, max_steps0); - let (iter1, steps1) = logspace_steps::>(ctx, 1, max_steps1); - let iter = iter0.flat_map(move |first| { - iter1.clone().map(move |second| (first, second)) - }); - let count = steps0.strict_mul(steps1); - (EitherIter::B(iter), count) - } + + // Binary test: `f16` may be exhaustive. + if let Some(steps0) = total_value_count::>() + && steps0 <= max_steps0 + && let Some(steps1) = total_value_count::>() + && steps1 <= max_steps1 + { + let iter = exhaustive_float() + .flat_map(|first| exhaustive_float().map(move |second| (first, second))); + let count = steps0.strict_mul(steps1); + + return (EitherIter::A(iter), count); } + + // Non-exhaustive, sweep a subset of inputs. + let (iter0, steps0) = logspace_steps::>(ctx, 0, max_steps0); + let (iter1, steps1) = logspace_steps::>(ctx, 1, max_steps1); + + let iter = + iter0.flat_map(move |first| iter1.clone().map(move |second| (first, second))); + let count = steps0.strict_mul(steps1); + + (EitherIter::B(iter), count) } } @@ -150,33 +157,39 @@ macro_rules! impl_spaced_input { let max_steps0 = iteration_count(ctx, 0); let max_steps1 = iteration_count(ctx, 1); let max_steps2 = iteration_count(ctx, 2); - // `f16` can be exhaustive tested if `LIBM_EXTENSIVE_TESTS` is incresed. - match total_value_count::>() { - Some(count) - if count <= max_steps0 && count <= max_steps1 && count <= max_steps2 => - { - let iter = exhaustive_float().flat_map(|first| { - exhaustive_float().flat_map(move |second| { - exhaustive_float().map(move |third| (first, second, third)) - }) - }); - (EitherIter::A(iter), count.checked_pow(3).unwrap()) - } - _ => { - let (iter0, steps0) = logspace_steps::>(ctx, 0, max_steps0); - let (iter1, steps1) = logspace_steps::>(ctx, 1, max_steps1); - let (iter2, steps2) = logspace_steps::>(ctx, 2, max_steps2); - - let iter = iter0 - .flat_map(move |first| iter1.clone().map(move |second| (first, second))) - .flat_map(move |(first, second)| { - iter2.clone().map(move |third| (first, second, third)) - }); - let count = steps0.strict_mul(steps1).strict_mul(steps2); - - (EitherIter::B(iter), count) - } + + // Ternary test: `f16` may be exhaustive tested if `LIBM_EXTENSIVE_TESTS` + // is incresed. + if let Some(steps0) = total_value_count::>() + && steps0 <= max_steps0 + && let Some(steps1) = total_value_count::>() + && steps1 <= max_steps1 + && let Some(steps2) = total_value_count::>() + && steps2 <= max_steps2 + { + let iter = exhaustive_float().flat_map(|first| { + exhaustive_float().flat_map(move |second| { + exhaustive_float().map(move |third| (first, second, third)) + }) + }); + let count = steps0.strict_mul(steps1).strict_mul(steps2); + + return (EitherIter::A(iter), count); } + + // Non-exhaustive, sweep a subset of inputs. + let (iter0, steps0) = logspace_steps::>(ctx, 0, max_steps0); + let (iter1, steps1) = logspace_steps::>(ctx, 1, max_steps1); + let (iter2, steps2) = logspace_steps::>(ctx, 2, max_steps2); + + let iter = iter0 + .flat_map(move |first| iter1.clone().map(move |second| (first, second))) + .flat_map(move |(first, second)| { + iter2.clone().map(move |third| (first, second, third)) + }); + let count = steps0.strict_mul(steps1).strict_mul(steps2); + + (EitherIter::B(iter), count) } } @@ -188,27 +201,29 @@ macro_rules! impl_spaced_input { let range0 = int_range(ctx, 0).unwrap_or(full_range()); let max_steps0 = iteration_count(ctx, 0); let max_steps1 = iteration_count(ctx, 1); - match total_value_count::>() { - Some(count1) if count1 <= max_steps1 => { - let (iter0, steps0) = linear_ints(range0, max_steps0); - let iter = iter0.flat_map(move |first| { - exhaustive_float().map(move |second| (first, second)) - }); - let count = steps0.strict_mul(count1); - (EitherIter::A(iter), count) - } - _ => { - let (iter0, steps0) = linear_ints(range0, max_steps0); - let (iter1, steps1) = logspace_steps::>(ctx, 1, max_steps1); - - let iter = iter0.flat_map(move |first| { - iter1.clone().map(move |second| (first, second)) - }); - let count = steps0.strict_mul(steps1); - - (EitherIter::B(iter), count) - } + + if let Some(steps0) = total_value_count_int::>() + && steps0 <= max_steps0 + && let Some(steps1) = total_value_count::>() + && steps1 <= max_steps1 + { + let (iter0, steps0) = linear_ints(range0, max_steps0); + let iter = iter0.flat_map(move |first| { + exhaustive_float().map(move |second| (first, second)) + }); + let count = steps0.strict_mul(steps1); + + return (EitherIter::A(iter), count); } + + let (iter0, steps0) = linear_ints(range0, max_steps0); + let (iter1, steps1) = logspace_steps::>(ctx, 1, max_steps1); + + let iter = + iter0.flat_map(move |first| iter1.clone().map(move |second| (first, second))); + let count = steps0.strict_mul(steps1); + + (EitherIter::B(iter), count) } } @@ -220,27 +235,26 @@ macro_rules! impl_spaced_input { let max_steps0 = iteration_count(ctx, 0); let range1 = int_range(ctx, 1).unwrap_or(full_range()); let max_steps1 = iteration_count(ctx, 1); - match total_value_count::>() { - Some(count0) if count0 <= max_steps0 => { - let (iter1, steps1) = linear_ints(range1, max_steps1); - let iter = exhaustive_float().flat_map(move |first| { - iter1.clone().map(move |second| (first, second)) - }); - let count = count0.strict_mul(steps1); - (EitherIter::A(iter), count) - } - _ => { - let (iter0, steps0) = logspace_steps::>(ctx, 0, max_steps0); - let (iter1, steps1) = linear_ints(range1, max_steps1); - - let iter = iter0.flat_map(move |first| { - iter1.clone().map(move |second| (first, second)) - }); - let count = steps0.strict_mul(steps1); - - (EitherIter::B(iter), count) - } + + if let Some(steps0) = total_value_count::>() + && steps0 <= max_steps0 + { + let (iter1, steps1) = linear_ints(range1, max_steps1); + let iter = exhaustive_float() + .flat_map(move |first| iter1.clone().map(move |second| (first, second))); + let count = steps0.strict_mul(steps1); + + return (EitherIter::A(iter), count); } + + let (iter0, steps0) = logspace_steps::>(ctx, 0, max_steps0); + let (iter1, steps1) = linear_ints(range1, max_steps1); + + let iter = + iter0.flat_map(move |first| iter1.clone().map(move |second| (first, second))); + let count = steps0.strict_mul(steps1); + + (EitherIter::B(iter), count) } } }; @@ -262,17 +276,17 @@ macro_rules! impl_spaced_input_int { fn get_cases(ctx: &CheckCtx) -> (impl Iterator, u64) { let range = int_range(ctx, 0).unwrap_or(full_range()); let max_steps0 = iteration_count(ctx, 0); - match total_value_count_int::>() { - Some(steps0) if steps0 <= max_steps0 => { - let iter0 = range.map(|v| (v,)); - (EitherIter::A(iter0), steps0) - } - _ => { - let (iter0, steps0) = linear_ints::>(range, max_steps0); - let iter0 = iter0.map(|v| (v,)); - (EitherIter::B(iter0), steps0) - } + + if let Some(steps0) = total_value_count_int::>() + && steps0 <= max_steps0 + { + let iter0 = range.map(|v| (v,)); + return (EitherIter::A(iter0), steps0); } + + let (iter0, steps0) = linear_ints::>(range, max_steps0); + let iter0 = iter0.map(|v| (v,)); + (EitherIter::B(iter0), steps0) } } @@ -285,24 +299,26 @@ macro_rules! impl_spaced_input_int { let range1 = int_range(ctx, 1).unwrap_or(full_range()); let max_steps0 = iteration_count(ctx, 0); let max_steps1 = iteration_count(ctx, 0); - match total_value_count_int::>() { - Some(count) if count <= max_steps0 && count < max_steps1 => { - let iter = range0.flat_map(move |first| { - range1.clone().map(move |second| (first, second)) - }); - let count = count.strict_mul(count); - (EitherIter::A(iter), count) - } - _ => { - let (iter0, steps0) = linear_ints::>(range0, max_steps0); - let (iter1, steps1) = linear_ints::>(range1, max_steps1); - let iter = iter0.flat_map(move |first| { - iter1.clone().map(move |second| (first, second)) - }); - let count = steps0.strict_mul(steps1); - (EitherIter::B(iter), count) - } + + if let Some(steps0) = total_value_count_int::>() + && steps0 <= max_steps0 + && let Some(steps1) = total_value_count_int::>() + && steps1 <= max_steps1 + { + let iter = range0 + .flat_map(move |first| range1.clone().map(move |second| (first, second))); + let count = steps0.strict_mul(steps1); + + return (EitherIter::A(iter), count); } + + let (iter0, steps0) = linear_ints::>(range0, max_steps0); + let (iter1, steps1) = linear_ints::>(range1, max_steps1); + let iter = + iter0.flat_map(move |first| iter1.clone().map(move |second| (first, second))); + let count = steps0.strict_mul(steps1); + + (EitherIter::B(iter), count) } } }; @@ -318,24 +334,25 @@ macro_rules! impl_spaced_input_int { let range1 = int_range(ctx, 1).unwrap_or(full_range()); let max_steps0 = iteration_count(ctx, 0); let max_steps1 = iteration_count(ctx, 0); - match total_value_count_int::>() { - Some(count) if count <= max_steps0 && count < max_steps1 => { - let iter = range0.flat_map(move |first| { - range1.clone().map(move |second| (first, second)) - }); - let count = count.strict_mul(count); - (EitherIter::A(iter), count) - } - _ => { - let (iter0, steps0) = linear_ints::>(range0, max_steps0); - let (iter1, steps1) = linear_ints::>(range1, max_steps1); - let iter = iter0.flat_map(move |first| { - iter1.clone().map(move |second| (first, second)) - }); - let count = steps0.strict_mul(steps1); - (EitherIter::B(iter), count) - } + + if let Some(steps0) = total_value_count_int::>() + && steps0 <= max_steps0 + && let Some(steps1) = total_value_count_int::>() + && steps1 <= max_steps1 + { + let iter = range0 + .flat_map(move |first| range1.clone().map(move |second| (first, second))); + let count = steps0.strict_mul(steps1); + + return (EitherIter::A(iter), count); } + + let (iter0, steps0) = linear_ints::>(range0, max_steps0); + let (iter1, steps1) = linear_ints::>(range1, max_steps1); + let iter = + iter0.flat_map(move |first| iter1.clone().map(move |second| (first, second))); + let count = steps0.strict_mul(steps1); + (EitherIter::B(iter), count) } } }; From bbcba28cfc2627b5a26bbea3df1643a0a614cdb6 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Tue, 7 Apr 2026 04:16:09 -0400 Subject: [PATCH 095/183] test: Use a more consistent setup for `iter` and `steps` --- .../libm-test/src/generate/edge_cases.rs | 16 ++-- .../libm-test/src/generate/random.rs | 62 +++++++++------ .../libm-test/src/generate/spaced.rs | 77 +++++++++++-------- 3 files changed, 89 insertions(+), 66 deletions(-) diff --git a/library/compiler-builtins/libm-test/src/generate/edge_cases.rs b/library/compiler-builtins/libm-test/src/generate/edge_cases.rs index 84ef5a2a36b43..56475cbffde54 100644 --- a/library/compiler-builtins/libm-test/src/generate/edge_cases.rs +++ b/library/compiler-builtins/libm-test/src/generate/edge_cases.rs @@ -244,7 +244,7 @@ macro_rules! impl_edge_case_input { let (iter1, steps1) = float_edge_cases::>(ctx, 1); let iter = iter0.flat_map(move |first| iter1.clone().map(move |second| (first, second))); - let count = steps0.checked_mul(steps1).unwrap(); + let count = steps0.strict_mul(steps1); (iter, count) } } @@ -263,11 +263,7 @@ macro_rules! impl_edge_case_input { .flat_map(move |(first, second)| { iter2.clone().map(move |third| (first, second, third)) }); - let count = steps0 - .checked_mul(steps1) - .unwrap() - .checked_mul(steps2) - .unwrap(); + let count = steps0.strict_mul(steps1).strict_mul(steps2); (iter, count) } @@ -283,7 +279,7 @@ macro_rules! impl_edge_case_input { let iter = iter0.flat_map(move |first| iter1.clone().map(move |second| (first, second))); - let count = steps0.checked_mul(steps1).unwrap(); + let count = steps0.strict_mul(steps1); (iter, count) } @@ -299,7 +295,7 @@ macro_rules! impl_edge_case_input { let iter = iter0.flat_map(move |first| iter1.clone().map(move |second| (first, second))); - let count = steps0.checked_mul(steps1).unwrap(); + let count = steps0.strict_mul(steps1); (iter, count) } @@ -336,7 +332,7 @@ macro_rules! impl_edge_case_input_int { let (iter1, steps1) = int_edge_cases(ctx, 1); let iter = iter0.flat_map(move |first| iter1.clone().map(move |second| (first, second))); - let count = steps0.checked_mul(steps1).unwrap(); + let count = steps0.strict_mul(steps1); (iter, count) } } @@ -353,7 +349,7 @@ macro_rules! impl_edge_case_input_int { let (iter1, steps1) = int_edge_cases(ctx, 1); let iter = iter0.flat_map(move |first| iter1.clone().map(move |second| (first, second))); - let count = steps0.checked_mul(steps1).unwrap(); + let count = steps0.strict_mul(steps1); (iter, count) } } diff --git a/library/compiler-builtins/libm-test/src/generate/random.rs b/library/compiler-builtins/libm-test/src/generate/random.rs index 6ce0df458d493..4b3eaea587202 100644 --- a/library/compiler-builtins/libm-test/src/generate/random.rs +++ b/library/compiler-builtins/libm-test/src/generate/random.rs @@ -33,7 +33,7 @@ pub trait RandomInput: Sized { } /// Generate a sequence of deterministically random floats. -fn random_floats(count: u64) -> impl Iterator +fn random_floats(count: u64) -> impl Iterator + Clone where StandardUniform: Distribution, { @@ -45,7 +45,7 @@ where } /// Generate a sequence of deterministically random `i32`s within a specified range. -fn random_ints(count: u64, range: RangeInclusive) -> impl Iterator +fn random_ints(count: u64, range: RangeInclusive) -> impl Iterator + Clone where I: Int + SampleUniform, { @@ -67,9 +67,12 @@ macro_rules! impl_random_input { fn get_cases(ctx: &CheckCtx) -> (impl Iterator, u64) { let count0 = iteration_count(ctx, 0); let count1 = iteration_count(ctx, 1); - let iter = random_floats(count0) - .flat_map(move |f1: $fty| random_floats(count1).map(move |f2: $fty| (f1, f2))); - (iter, count0 * count1) + let iter0 = random_floats(count0); + let iter1 = random_floats(count1); + let iter = + iter0.flat_map(move |first| iter1.clone().map(move |second| (first, second))); + let count = count0.strict_mul(count1); + (iter, count) } } @@ -78,12 +81,16 @@ macro_rules! impl_random_input { let count0 = iteration_count(ctx, 0); let count1 = iteration_count(ctx, 1); let count2 = iteration_count(ctx, 2); - let iter = random_floats(count0).flat_map(move |f1: $fty| { - random_floats(count1).flat_map(move |f2: $fty| { - random_floats(count2).map(move |f3: $fty| (f1, f2, f3)) - }) - }); - (iter, count0 * count1 * count2) + let iter0 = random_floats(count0); + let iter1 = random_floats(count1); + let iter2 = random_floats(count2); + let iter = iter0 + .flat_map(move |first| iter1.clone().map(move |second| (first, second))) + .flat_map(move |(first, second)| { + iter2.clone().map(move |third| (first, second, third)) + }); + let count = count0.strict_mul(count1).strict_mul(count2); + (iter, count) } } @@ -92,9 +99,12 @@ macro_rules! impl_random_input { let count0 = iteration_count(ctx, 0); let count1 = iteration_count(ctx, 1); let range0 = int_range::(ctx, 0).unwrap_or(full_range()); - let iter = random_ints(count0, range0) - .flat_map(move |f1: i32| random_floats(count1).map(move |f2: $fty| (f1, f2))); - (iter, count0 * count1) + let iter0 = random_ints(count0, range0); + let iter1 = random_floats(count1); + let iter = + iter0.flat_map(move |first| iter1.clone().map(move |second| (first, second))); + let count = count0.strict_mul(count1); + (iter, count) } } @@ -103,10 +113,12 @@ macro_rules! impl_random_input { let count0 = iteration_count(ctx, 0); let count1 = iteration_count(ctx, 1); let range1 = int_range::(ctx, 1).unwrap_or(full_range()); - let iter = random_floats(count0).flat_map(move |f1: $fty| { - random_ints(count1, range1.clone()).map(move |f2: i32| (f1, f2)) - }); - (iter, count0 * count1) + let iter0 = random_floats(count0); + let iter1 = random_ints(count1, range1.clone()); + let iter = + iter0.flat_map(move |first| iter1.clone().map(move |second| (first, second))); + let count = count0.strict_mul(count1); + (iter, count) } } }; @@ -136,9 +148,10 @@ macro_rules! impl_random_input_int { let count1 = iteration_count(ctx, 1); let range0 = int_range::<$ity>(ctx, 0).unwrap_or(full_range()); let range1 = int_range::<$ity>(ctx, 1).unwrap_or(full_range()); - let iter = random_ints(count0, range0).flat_map(move |f1: $ity| { - random_ints(count1, range1.clone()).map(move |f2: $ity| (f1, f2)) - }); + let iter0 = random_ints(count0, range0); + let iter1 = random_ints(count1, range1.clone()); + let iter = + iter0.flat_map(move |first| iter1.clone().map(move |second| (first, second))); (iter, count0 * count1) } } @@ -152,9 +165,10 @@ macro_rules! impl_random_input_int { let count1 = iteration_count(ctx, 1); let range0 = int_range::<$ity>(ctx, 0).unwrap_or(full_range()); let range1 = int_range::(ctx, 1).unwrap_or(full_range()); - let iter = random_ints(count0, range0).flat_map(move |f1: $ity| { - random_ints(count1, range1.clone()).map(move |f2: u32| (f1, f2)) - }); + let iter0 = random_ints(count0, range0); + let iter1 = random_ints(count1, range1.clone()); + let iter = + iter0.flat_map(move |first| iter1.clone().map(move |second| (first, second))); (iter, count0 * count1) } } diff --git a/library/compiler-builtins/libm-test/src/generate/spaced.rs b/library/compiler-builtins/libm-test/src/generate/spaced.rs index ba04b99512729..38a8b45f1d690 100644 --- a/library/compiler-builtins/libm-test/src/generate/spaced.rs +++ b/library/compiler-builtins/libm-test/src/generate/spaced.rs @@ -83,11 +83,14 @@ where } /// Returns an iterator of every possible value of type `F`. -fn exhaustive_float() -> impl Iterator +fn exhaustive_float() -> (impl Iterator + Clone, u64) where + u64: TryFrom, RangeInclusive: Iterator, { - (F::Int::MIN..=F::Int::MAX).map(|bits| F::from_bits(bits)) + let count = total_value_count::().expect("tried exhaustive with > u64::MAX items"); + let iter = (F::Int::MIN..=F::Int::MAX).map(|bits| F::from_bits(bits)); + (iter, count) } macro_rules! impl_spaced_input { @@ -100,10 +103,10 @@ macro_rules! impl_spaced_input { let max_steps0 = iteration_count(ctx, 0); // Unary tests: `f16` and `f32` may be exhaustive. - if let Some(steps0) = total_value_count::>() - && steps0 <= max_steps0 + if let Some(exhaustive_steps0) = total_value_count::>() + && exhaustive_steps0 <= max_steps0 { - let iter0 = exhaustive_float(); + let (iter0, steps0) = exhaustive_float(); let iter0 = iter0.map(|v| (v,)); return (EitherIter::A(iter0), steps0); @@ -125,13 +128,16 @@ macro_rules! impl_spaced_input { let max_steps1 = iteration_count(ctx, 1); // Binary test: `f16` may be exhaustive. - if let Some(steps0) = total_value_count::>() - && steps0 <= max_steps0 - && let Some(steps1) = total_value_count::>() - && steps1 <= max_steps1 + if let Some(exhaustive_steps0) = total_value_count::>() + && exhaustive_steps0 <= max_steps0 + && let Some(exhaustive_steps1) = total_value_count::>() + && exhaustive_steps1 <= max_steps1 { - let iter = exhaustive_float() - .flat_map(|first| exhaustive_float().map(move |second| (first, second))); + let (iter0, steps0) = exhaustive_float(); + let (iter1, steps1) = exhaustive_float(); + + let iter = iter0 + .flat_map(move |first| iter1.clone().map(move |second| (first, second))); let count = steps0.strict_mul(steps1); return (EitherIter::A(iter), count); @@ -160,18 +166,22 @@ macro_rules! impl_spaced_input { // Ternary test: `f16` may be exhaustive tested if `LIBM_EXTENSIVE_TESTS` // is incresed. - if let Some(steps0) = total_value_count::>() - && steps0 <= max_steps0 - && let Some(steps1) = total_value_count::>() - && steps1 <= max_steps1 - && let Some(steps2) = total_value_count::>() - && steps2 <= max_steps2 + if let Some(exhaustive_steps0) = total_value_count::>() + && exhaustive_steps0 <= max_steps0 + && let Some(exhaustive_steps1) = total_value_count::>() + && exhaustive_steps1 <= max_steps1 + && let Some(exhaustive_steps2) = total_value_count::>() + && exhaustive_steps2 <= max_steps2 { - let iter = exhaustive_float().flat_map(|first| { - exhaustive_float().flat_map(move |second| { - exhaustive_float().map(move |third| (first, second, third)) - }) - }); + let (iter0, steps0) = exhaustive_float(); + let (iter1, steps1) = exhaustive_float(); + let (iter2, steps2) = exhaustive_float(); + + let iter = iter0 + .flat_map(move |first| iter1.clone().map(move |second| (first, second))) + .flat_map(move |(first, second)| { + iter2.clone().map(move |third| (first, second, third)) + }); let count = steps0.strict_mul(steps1).strict_mul(steps2); return (EitherIter::A(iter), count); @@ -202,15 +212,16 @@ macro_rules! impl_spaced_input { let max_steps0 = iteration_count(ctx, 0); let max_steps1 = iteration_count(ctx, 1); - if let Some(steps0) = total_value_count_int::>() - && steps0 <= max_steps0 - && let Some(steps1) = total_value_count::>() - && steps1 <= max_steps1 + if let Some(exhaustive_steps0) = total_value_count_int::>() + && exhaustive_steps0 <= max_steps0 + && let Some(exhaustive_steps1) = total_value_count::>() + && exhaustive_steps1 <= max_steps1 { let (iter0, steps0) = linear_ints(range0, max_steps0); - let iter = iter0.flat_map(move |first| { - exhaustive_float().map(move |second| (first, second)) - }); + let (iter1, steps1) = exhaustive_float(); + + let iter = iter0 + .flat_map(move |first| iter1.clone().map(move |second| (first, second))); let count = steps0.strict_mul(steps1); return (EitherIter::A(iter), count); @@ -236,11 +247,13 @@ macro_rules! impl_spaced_input { let range1 = int_range(ctx, 1).unwrap_or(full_range()); let max_steps1 = iteration_count(ctx, 1); - if let Some(steps0) = total_value_count::>() - && steps0 <= max_steps0 + if let Some(exhaustive_steps0) = total_value_count::>() + && exhaustive_steps0 <= max_steps0 { + let (iter0, steps0) = exhaustive_float(); let (iter1, steps1) = linear_ints(range1, max_steps1); - let iter = exhaustive_float() + + let iter = iter0 .flat_map(move |first| iter1.clone().map(move |second| (first, second))); let count = steps0.strict_mul(steps1); From 25104546cee636e4009f1d0d90175d9f38db108e Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Tue, 7 Apr 2026 04:37:56 -0400 Subject: [PATCH 096/183] test: Extract `flat_map`s to `product*` functions --- .../libm-test/src/generate.rs | 25 ++++++++++ .../libm-test/src/generate/edge_cases.rs | 23 +++------ .../libm-test/src/generate/random.rs | 23 +++------ .../libm-test/src/generate/spaced.rs | 47 +++++++------------ 4 files changed, 55 insertions(+), 63 deletions(-) diff --git a/library/compiler-builtins/libm-test/src/generate.rs b/library/compiler-builtins/libm-test/src/generate.rs index da080d23fa79c..7118752f4f0bb 100644 --- a/library/compiler-builtins/libm-test/src/generate.rs +++ b/library/compiler-builtins/libm-test/src/generate.rs @@ -48,3 +48,28 @@ impl Iterator for KnownSize { } impl ExactSizeIterator for KnownSize {} + +/// Yield `(a0, b0), ..., (a0, bn), ..., (an, bn)` for iterators `[a0, ..., an]` and +/// `[b0, ..., bn]`. +fn product2(i0: I0, i1: I1) -> impl Iterator +where + I0: Iterator, + I1: Iterator + Clone, +{ + i0.flat_map(move |first| i1.clone().map(move |second| (first, second))) +} + +/// Yield `(a0, b0, c0), ..., (a0, b0, cn), ..., (a0, bn, cn), ..., (an, bn, cn)` for iterators +/// `[a0, ..., an]`, `[b0, ..., bn]` and `[c0, ..., cn]`. +fn product3( + i0: I0, + i1: I1, + i2: I2, +) -> impl Iterator +where + I0: Iterator, + I1: Iterator + Clone, + I2: Iterator + Clone, +{ + product2(product2(i0, i1), i2).map(|((first, second), third)| (first, second, third)) +} diff --git a/library/compiler-builtins/libm-test/src/generate/edge_cases.rs b/library/compiler-builtins/libm-test/src/generate/edge_cases.rs index 56475cbffde54..9ada6d5c95b2d 100644 --- a/library/compiler-builtins/libm-test/src/generate/edge_cases.rs +++ b/library/compiler-builtins/libm-test/src/generate/edge_cases.rs @@ -3,7 +3,7 @@ use libm::support::{CastInto, Float, Int, MinInt}; use crate::domain::get_domain; -use crate::generate::KnownSize; +use crate::generate::{KnownSize, product2, product3}; use crate::run_cfg::{check_near_count, check_point_count}; use crate::{Arg0, Arg1, Arg2, BaseName, CheckCtx, FloatExt, MathOp, Ty, test_log}; @@ -242,8 +242,7 @@ macro_rules! impl_edge_case_input { fn get_cases(ctx: &CheckCtx) -> (impl Iterator, u64) { let (iter0, steps0) = float_edge_cases::>(ctx, 0); let (iter1, steps1) = float_edge_cases::>(ctx, 1); - let iter = - iter0.flat_map(move |first| iter1.clone().map(move |second| (first, second))); + let iter = product2(iter0, iter1); let count = steps0.strict_mul(steps1); (iter, count) } @@ -258,11 +257,7 @@ macro_rules! impl_edge_case_input { let (iter1, steps1) = float_edge_cases::>(ctx, 1); let (iter2, steps2) = float_edge_cases::>(ctx, 2); - let iter = iter0 - .flat_map(move |first| iter1.clone().map(move |second| (first, second))) - .flat_map(move |(first, second)| { - iter2.clone().map(move |third| (first, second, third)) - }); + let iter = product3(iter0, iter1, iter2); let count = steps0.strict_mul(steps1).strict_mul(steps2); (iter, count) @@ -277,8 +272,7 @@ macro_rules! impl_edge_case_input { let (iter0, steps0) = int_edge_cases(ctx, 0); let (iter1, steps1) = float_edge_cases::>(ctx, 1); - let iter = - iter0.flat_map(move |first| iter1.clone().map(move |second| (first, second))); + let iter = product2(iter0, iter1); let count = steps0.strict_mul(steps1); (iter, count) @@ -293,8 +287,7 @@ macro_rules! impl_edge_case_input { let (iter0, steps0) = float_edge_cases::>(ctx, 0); let (iter1, steps1) = int_edge_cases(ctx, 1); - let iter = - iter0.flat_map(move |first| iter1.clone().map(move |second| (first, second))); + let iter = product2(iter0, iter1); let count = steps0.strict_mul(steps1); (iter, count) @@ -330,8 +323,7 @@ macro_rules! impl_edge_case_input_int { fn get_cases(ctx: &CheckCtx) -> (impl Iterator, u64) { let (iter0, steps0) = int_edge_cases(ctx, 0); let (iter1, steps1) = int_edge_cases(ctx, 1); - let iter = - iter0.flat_map(move |first| iter1.clone().map(move |second| (first, second))); + let iter = product2(iter0, iter1); let count = steps0.strict_mul(steps1); (iter, count) } @@ -347,8 +339,7 @@ macro_rules! impl_edge_case_input_int { fn get_cases(ctx: &CheckCtx) -> (impl Iterator, u64) { let (iter0, steps0) = int_edge_cases(ctx, 0); let (iter1, steps1) = int_edge_cases(ctx, 1); - let iter = - iter0.flat_map(move |first| iter1.clone().map(move |second| (first, second))); + let iter = product2(iter0, iter1); let count = steps0.strict_mul(steps1); (iter, count) } diff --git a/library/compiler-builtins/libm-test/src/generate/random.rs b/library/compiler-builtins/libm-test/src/generate/random.rs index 4b3eaea587202..32bd2f24ee044 100644 --- a/library/compiler-builtins/libm-test/src/generate/random.rs +++ b/library/compiler-builtins/libm-test/src/generate/random.rs @@ -9,8 +9,8 @@ use rand::prelude::Distribution; use rand::{RngExt, SeedableRng}; use rand_chacha::ChaCha8Rng; -use super::KnownSize; use crate::CheckCtx; +use crate::generate::{KnownSize, product2, product3}; use crate::num::full_range; use crate::run_cfg::{int_range, iteration_count}; @@ -69,8 +69,7 @@ macro_rules! impl_random_input { let count1 = iteration_count(ctx, 1); let iter0 = random_floats(count0); let iter1 = random_floats(count1); - let iter = - iter0.flat_map(move |first| iter1.clone().map(move |second| (first, second))); + let iter = product2(iter0, iter1); let count = count0.strict_mul(count1); (iter, count) } @@ -84,11 +83,7 @@ macro_rules! impl_random_input { let iter0 = random_floats(count0); let iter1 = random_floats(count1); let iter2 = random_floats(count2); - let iter = iter0 - .flat_map(move |first| iter1.clone().map(move |second| (first, second))) - .flat_map(move |(first, second)| { - iter2.clone().map(move |third| (first, second, third)) - }); + let iter = product3(iter0, iter1, iter2); let count = count0.strict_mul(count1).strict_mul(count2); (iter, count) } @@ -101,8 +96,7 @@ macro_rules! impl_random_input { let range0 = int_range::(ctx, 0).unwrap_or(full_range()); let iter0 = random_ints(count0, range0); let iter1 = random_floats(count1); - let iter = - iter0.flat_map(move |first| iter1.clone().map(move |second| (first, second))); + let iter = product2(iter0, iter1); let count = count0.strict_mul(count1); (iter, count) } @@ -115,8 +109,7 @@ macro_rules! impl_random_input { let range1 = int_range::(ctx, 1).unwrap_or(full_range()); let iter0 = random_floats(count0); let iter1 = random_ints(count1, range1.clone()); - let iter = - iter0.flat_map(move |first| iter1.clone().map(move |second| (first, second))); + let iter = product2(iter0, iter1); let count = count0.strict_mul(count1); (iter, count) } @@ -150,8 +143,7 @@ macro_rules! impl_random_input_int { let range1 = int_range::<$ity>(ctx, 1).unwrap_or(full_range()); let iter0 = random_ints(count0, range0); let iter1 = random_ints(count1, range1.clone()); - let iter = - iter0.flat_map(move |first| iter1.clone().map(move |second| (first, second))); + let iter = product2(iter0, iter1); (iter, count0 * count1) } } @@ -167,8 +159,7 @@ macro_rules! impl_random_input_int { let range1 = int_range::(ctx, 1).unwrap_or(full_range()); let iter0 = random_ints(count0, range0); let iter1 = random_ints(count1, range1.clone()); - let iter = - iter0.flat_map(move |first| iter1.clone().map(move |second| (first, second))); + let iter = product2(iter0, iter1); (iter, count0 * count1) } } diff --git a/library/compiler-builtins/libm-test/src/generate/spaced.rs b/library/compiler-builtins/libm-test/src/generate/spaced.rs index 38a8b45f1d690..192106cc61827 100644 --- a/library/compiler-builtins/libm-test/src/generate/spaced.rs +++ b/library/compiler-builtins/libm-test/src/generate/spaced.rs @@ -4,6 +4,7 @@ use std::ops::RangeInclusive; use libm::support::{Float, Int, MinInt}; use crate::domain::get_domain; +use crate::generate::{product2, product3}; use crate::num::full_range; use crate::run_cfg::{int_range, iteration_count}; use crate::{Arg0, Arg1, Arg2, CheckCtx, MathOp, linear_ints, logspace}; @@ -136,8 +137,7 @@ macro_rules! impl_spaced_input { let (iter0, steps0) = exhaustive_float(); let (iter1, steps1) = exhaustive_float(); - let iter = iter0 - .flat_map(move |first| iter1.clone().map(move |second| (first, second))); + let iter = product2(iter0, iter1); let count = steps0.strict_mul(steps1); return (EitherIter::A(iter), count); @@ -147,8 +147,7 @@ macro_rules! impl_spaced_input { let (iter0, steps0) = logspace_steps::>(ctx, 0, max_steps0); let (iter1, steps1) = logspace_steps::>(ctx, 1, max_steps1); - let iter = - iter0.flat_map(move |first| iter1.clone().map(move |second| (first, second))); + let iter = product2(iter0, iter1); let count = steps0.strict_mul(steps1); (EitherIter::B(iter), count) @@ -177,11 +176,7 @@ macro_rules! impl_spaced_input { let (iter1, steps1) = exhaustive_float(); let (iter2, steps2) = exhaustive_float(); - let iter = iter0 - .flat_map(move |first| iter1.clone().map(move |second| (first, second))) - .flat_map(move |(first, second)| { - iter2.clone().map(move |third| (first, second, third)) - }); + let iter = product3(iter0, iter1, iter2); let count = steps0.strict_mul(steps1).strict_mul(steps2); return (EitherIter::A(iter), count); @@ -192,11 +187,7 @@ macro_rules! impl_spaced_input { let (iter1, steps1) = logspace_steps::>(ctx, 1, max_steps1); let (iter2, steps2) = logspace_steps::>(ctx, 2, max_steps2); - let iter = iter0 - .flat_map(move |first| iter1.clone().map(move |second| (first, second))) - .flat_map(move |(first, second)| { - iter2.clone().map(move |third| (first, second, third)) - }); + let iter = product3(iter0, iter1, iter2); let count = steps0.strict_mul(steps1).strict_mul(steps2); (EitherIter::B(iter), count) @@ -220,8 +211,7 @@ macro_rules! impl_spaced_input { let (iter0, steps0) = linear_ints(range0, max_steps0); let (iter1, steps1) = exhaustive_float(); - let iter = iter0 - .flat_map(move |first| iter1.clone().map(move |second| (first, second))); + let iter = product2(iter0, iter1); let count = steps0.strict_mul(steps1); return (EitherIter::A(iter), count); @@ -230,8 +220,7 @@ macro_rules! impl_spaced_input { let (iter0, steps0) = linear_ints(range0, max_steps0); let (iter1, steps1) = logspace_steps::>(ctx, 1, max_steps1); - let iter = - iter0.flat_map(move |first| iter1.clone().map(move |second| (first, second))); + let iter = product2(iter0, iter1); let count = steps0.strict_mul(steps1); (EitherIter::B(iter), count) @@ -253,8 +242,7 @@ macro_rules! impl_spaced_input { let (iter0, steps0) = exhaustive_float(); let (iter1, steps1) = linear_ints(range1, max_steps1); - let iter = iter0 - .flat_map(move |first| iter1.clone().map(move |second| (first, second))); + let iter = product2(iter0, iter1); let count = steps0.strict_mul(steps1); return (EitherIter::A(iter), count); @@ -263,8 +251,7 @@ macro_rules! impl_spaced_input { let (iter0, steps0) = logspace_steps::>(ctx, 0, max_steps0); let (iter1, steps1) = linear_ints(range1, max_steps1); - let iter = - iter0.flat_map(move |first| iter1.clone().map(move |second| (first, second))); + let iter = product2(iter0, iter1); let count = steps0.strict_mul(steps1); (EitherIter::B(iter), count) @@ -315,11 +302,10 @@ macro_rules! impl_spaced_input_int { if let Some(steps0) = total_value_count_int::>() && steps0 <= max_steps0 - && let Some(steps1) = total_value_count_int::>() + && let Some(steps1) = total_value_count_int::>() && steps1 <= max_steps1 { - let iter = range0 - .flat_map(move |first| range1.clone().map(move |second| (first, second))); + let iter = product2(range0, range1); let count = steps0.strict_mul(steps1); return (EitherIter::A(iter), count); @@ -327,8 +313,8 @@ macro_rules! impl_spaced_input_int { let (iter0, steps0) = linear_ints::>(range0, max_steps0); let (iter1, steps1) = linear_ints::>(range1, max_steps1); - let iter = - iter0.flat_map(move |first| iter1.clone().map(move |second| (first, second))); + + let iter = product2(iter0, iter1); let count = steps0.strict_mul(steps1); (EitherIter::B(iter), count) @@ -353,8 +339,7 @@ macro_rules! impl_spaced_input_int { && let Some(steps1) = total_value_count_int::>() && steps1 <= max_steps1 { - let iter = range0 - .flat_map(move |first| range1.clone().map(move |second| (first, second))); + let iter = product2(range0, range1); let count = steps0.strict_mul(steps1); return (EitherIter::A(iter), count); @@ -362,8 +347,8 @@ macro_rules! impl_spaced_input_int { let (iter0, steps0) = linear_ints::>(range0, max_steps0); let (iter1, steps1) = linear_ints::>(range1, max_steps1); - let iter = - iter0.flat_map(move |first| iter1.clone().map(move |second| (first, second))); + + let iter = product2(iter0, iter1); let count = steps0.strict_mul(steps1); (EitherIter::B(iter), count) } From 2b288d32b5ceaa486ad6047c7e973926515f21c1 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Wed, 1 Apr 2026 19:26:44 -0400 Subject: [PATCH 097/183] build: Make c-b `configue::Target` match libm `configure::Config` Rename the fields and the type use to make it easier to combine these two structs. --- .../builtins-test-intrinsics/build.rs | 4 +- .../compiler-builtins/builtins-test/build.rs | 44 +++--- .../compiler-builtins/build.rs | 138 +++++++++--------- .../compiler-builtins/configure.rs | 67 ++++----- 4 files changed, 128 insertions(+), 125 deletions(-) diff --git a/library/compiler-builtins/builtins-test-intrinsics/build.rs b/library/compiler-builtins/builtins-test-intrinsics/build.rs index b82581262f7b0..4dcad9e459917 100644 --- a/library/compiler-builtins/builtins-test-intrinsics/build.rs +++ b/library/compiler-builtins/builtins-test-intrinsics/build.rs @@ -5,6 +5,6 @@ mod builtins_configure { fn main() { println!("cargo::rerun-if-changed=../configure.rs"); - let target = builtins_configure::Target::from_env(); - builtins_configure::configure_aliases(&target); + let cfg = builtins_configure::Config::from_env(); + builtins_configure::configure_aliases(&cfg); } diff --git a/library/compiler-builtins/builtins-test/build.rs b/library/compiler-builtins/builtins-test/build.rs index 46179cc7ffcf9..af688c00cff26 100644 --- a/library/compiler-builtins/builtins-test/build.rs +++ b/library/compiler-builtins/builtins-test/build.rs @@ -47,32 +47,32 @@ impl SetCfg { fn main() { println!("cargo::rerun-if-changed=../configure.rs"); - let target = builtins_configure::Target::from_env(); + let cfg = builtins_configure::Config::from_env(); let mut to_set = HashSet::new(); // These platforms do not have f128 symbols available in their system libraries, so // skip related tests. - if target.arch == "arm" - || target.vendor == "apple" - || target.env == "msvc" + if cfg.target_arch == "arm" + || cfg.target_vendor == "apple" + || cfg.target_env == "msvc" // GCC and LLVM disagree on the ABI of `f16` and `f128` with MinGW. See // . - || (target.os == "windows" && target.env == "gnu") + || (cfg.target_os == "windows" && cfg.target_env == "gnu") // FIXME(llvm): There is an ABI incompatibility between GCC and Clang on 32-bit x86. // See . - || target.arch == "x86" + || cfg.target_arch == "x86" // 32-bit PowerPC and 64-bit LE gets code generated that Qemu cannot handle. See // . - || target.arch == "powerpc" - || target.arch == "powerpc64le" + || cfg.target_arch == "powerpc" + || cfg.target_arch == "powerpc64le" // FIXME: We get different results from the builtin functions. See // . - || target.arch == "powerpc64" + || cfg.target_arch == "powerpc64" { to_set.insert(SetCfg::NoSysF128); } - if target.arch == "x86" { + if cfg.target_arch == "x86" { // 32-bit x86 does not have `__fixunstfti`/`__fixtfti` but does have everything else to_set.insert(SetCfg::NoSysF128IntConvert); // FIXME: 32-bit x86 has a bug in `f128 -> f16` system libraries @@ -81,25 +81,25 @@ fn main() { // These platforms do not have f16 symbols available in their system libraries, so // skip related tests. Most of these are missing `f16 <-> f32` conversion routines. - if (target.arch == "aarch64" && target.os == "linux") - || target.arch.starts_with("arm") - || target.arch == "powerpc" - || target.arch == "powerpc64" - || target.arch == "powerpc64le" - || target.arch == "loongarch64" - || (target.arch == "x86" && !target.has_feature("sse")) - || target.os == "windows" + if (cfg.target_arch == "aarch64" && cfg.target_os == "linux") + || cfg.target_arch.starts_with("arm") + || cfg.target_arch == "powerpc" + || cfg.target_arch == "powerpc64" + || cfg.target_arch == "powerpc64le" + || cfg.target_arch == "loongarch64" + || (cfg.target_arch == "x86" && !cfg.has_target_feature("sse")) + || cfg.target_os == "windows" // Linking says "error: function signature mismatch: __extendhfsf2" and seems to // think the signature is either `(i32) -> f32` or `(f32) -> f32`. See // . - || target.arch == "wasm32" - || target.arch == "wasm64" + || cfg.target_arch == "wasm32" + || cfg.target_arch == "wasm64" { to_set.insert(SetCfg::NoSysF16); } // These platforms are missing either `__extendhfdf2` or `__truncdfhf2`. - if target.vendor == "apple" || target.os == "windows" { + if cfg.target_vendor == "apple" || cfg.target_os == "windows" { to_set.insert(SetCfg::NoSysF16F64Convert); } @@ -116,5 +116,5 @@ fn main() { builtins_configure::set_cfg(cfg.name(), to_set.contains(cfg)); } - builtins_configure::configure_aliases(&target); + builtins_configure::configure_aliases(&cfg); } diff --git a/library/compiler-builtins/compiler-builtins/build.rs b/library/compiler-builtins/compiler-builtins/build.rs index b845b538e4f86..c86d3e588e41c 100644 --- a/library/compiler-builtins/compiler-builtins/build.rs +++ b/library/compiler-builtins/compiler-builtins/build.rs @@ -2,19 +2,19 @@ mod configure; use std::env; -use configure::{Target, configure_aliases, set_cfg}; +use configure::{Config, configure_aliases, set_cfg}; fn main() { println!("cargo::rerun-if-changed=build.rs"); println!("cargo::rerun-if-changed=configure.rs"); - let target = Target::from_env(); + let cfg = Config::from_env(); let cwd = env::current_dir().unwrap(); configure_check_cfg(); - configure_aliases(&target); + configure_aliases(&cfg); - configure_libm(&target); + configure_libm(&cfg); println!("cargo:compiler-rt={}", cwd.join("compiler-rt").display()); @@ -22,12 +22,12 @@ fn main() { println!("cargo::rustc-check-cfg=cfg(feature, values(\"mem-unaligned\"))"); // Emscripten's runtime includes all the builtins - if target.os == "emscripten" { + if cfg.target_os == "emscripten" { return; } // OpenBSD provides compiler_rt by default, use it instead of rebuilding it from source - if target.os == "openbsd" { + if cfg.target_os == "openbsd" { println!("cargo:rustc-link-search=native=/usr/lib"); println!("cargo:rustc-link-lib=compiler_rt"); return; @@ -35,27 +35,27 @@ fn main() { // Forcibly enable memory intrinsics on wasm & SGX as we don't have a libc to // provide them. - if (target.triple.contains("wasm") && !target.triple.contains("wasi")) - || (target.triple.contains("sgx") && target.triple.contains("fortanix")) - || target.triple.contains("-none") - || target.triple.contains("nvptx") - || target.triple.contains("uefi") - || target.triple.contains("xous") + if (cfg.target_triple.contains("wasm") && !cfg.target_triple.contains("wasi")) + || (cfg.target_triple.contains("sgx") && cfg.target_triple.contains("fortanix")) + || cfg.target_triple.contains("-none") + || cfg.target_triple.contains("nvptx") + || cfg.target_triple.contains("uefi") + || cfg.target_triple.contains("xous") { println!("cargo:rustc-cfg=feature=\"mem\""); } // These targets have hardware unaligned access support. - let mem_unaligned = target.arch.contains("x86_64") - || target.arch.contains("x86") - || target.arch.contains("aarch64") - || target.arch.contains("bpf"); + let mem_unaligned = cfg.target_arch.contains("x86_64") + || cfg.target_arch.contains("x86") + || cfg.target_arch.contains("aarch64") + || cfg.target_arch.contains("bpf"); set_cfg("mem_unaligned", mem_unaligned); // NOTE we are going to assume that llvm-target, what determines our codegen option, matches the // target triple. This is usually correct for our built-in targets but can break in presence of // custom targets, which can have arbitrary names. - let llvm_target = target.triple.split('-').collect::>(); + let llvm_target = cfg.target_triple.split('-').collect::>(); // Build missing intrinsics from compiler-rt C source code. If we're // mangling names though we assume that we're also in test mode so we don't @@ -65,9 +65,9 @@ fn main() { // Don't use a C compiler for these targets: // // * nvptx - everything is bitcode, not compatible with mixed C/Rust - if !target.arch.contains("nvptx") { + if !cfg.target_arch.contains("nvptx") { #[cfg(feature = "c")] - c::compile(&llvm_target, &target); + c::compile(&llvm_target, &cfg); } } @@ -76,28 +76,31 @@ fn main() { // rustc target (arm-linux-androideabi). let kernel_user_helpers = llvm_target[0] == "armv4t" || llvm_target[0] == "armv5te" - || target.triple == "arm-linux-androideabi"; + || cfg.target_triple == "arm-linux-androideabi"; set_cfg("kernel_user_helpers", kernel_user_helpers); } /// Run configuration for `libm` since it is included directly. /// /// Much of this is copied from `libm/configure.rs`. -fn configure_libm(target: &Target) { +fn configure_libm(cfg: &Config) { println!("cargo:rustc-check-cfg=cfg(feature, values(\"unstable-public-internals\"))"); // Always use intrinsics set_cfg("intrinsics_enabled", true); - let opt = !matches!(target.opt_level.as_str(), "0" | "1"); + let opt = !matches!(cfg.opt_level.as_str(), "0" | "1"); set_cfg("optimizations_enabled", opt); println!( "cargo:rustc-env=CFG_CARGO_FEATURES={:?}", - target.cargo_features + cfg.cargo_features + ); + println!("cargo:rustc-env=CFG_OPT_LEVEL={}", cfg.opt_level); + println!( + "cargo:rustc-env=CFG_TARGET_FEATURES={:?}", + cfg.target_features ); - println!("cargo:rustc-env=CFG_OPT_LEVEL={}", target.opt_level); - println!("cargo:rustc-env=CFG_TARGET_FEATURES={:?}", target.features); // Activate libm's unstable features to make full use of Nightly. println!("cargo:rustc-cfg=feature=\"unstable-intrinsics\""); @@ -176,7 +179,7 @@ mod c { use std::io::Write; use std::path::{Path, PathBuf}; - use super::Target; + use super::Config; struct Sources { // SYMBOL -> PATH TO SOURCE @@ -218,17 +221,17 @@ mod c { } /// Compile intrinsics from the compiler-rt C source code - pub fn compile(llvm_target: &[&str], target: &Target) { + pub fn compile(llvm_target: &[&str], cfg: &Config) { let mut consider_float_intrinsics = true; - let cfg = &mut cc::Build::new(); + let build = &mut cc::Build::new(); // AArch64 GCCs exit with an error condition when they encounter any kind of floating point // code if the `nofp` and/or `nosimd` compiler flags have been set. // // Therefore, evaluate if those flags are present and set a boolean that causes any // compiler-rt intrinsics that contain floating point source to be excluded for this target. - if target.arch == "aarch64" { - let cflags_key = String::from("CFLAGS_") + &(target.triple.replace("-", "_")); + if cfg.target_arch == "aarch64" { + let cflags_key = String::from("CFLAGS_") + &(cfg.target_triple.replace("-", "_")); if let Ok(cflags_value) = env::var(cflags_key) { if cflags_value.contains("+nofp") || cflags_value.contains("+nosimd") { consider_float_intrinsics = false; @@ -242,22 +245,22 @@ mod c { // support `_Float16` on all targets (whereas Rust does). However, define the macro // anyway to prevent issues like rust#118813 and rust#123885 silently reoccuring if more // `f16` intrinsics get accidentally added here in the future. - cfg.define("COMPILER_RT_HAS_FLOAT16", None); + build.define("COMPILER_RT_HAS_FLOAT16", None); - cfg.warnings(false); + build.warnings(false); - if target.env == "msvc" { + if cfg.target_env == "msvc" { // Don't pull in extra libraries on MSVC - cfg.flag("/Zl"); + build.flag("/Zl"); // Emulate C99 and C++11's __func__ for MSVC prior to 2013 CTP - cfg.define("__func__", Some("__FUNCTION__")); + build.define("__func__", Some("__FUNCTION__")); } else { // Turn off various features of gcc and such, mostly copying // compiler-rt's build system already - cfg.flag("-fno-builtin"); - cfg.flag("-fvisibility=hidden"); - cfg.flag("-ffreestanding"); + build.flag("-fno-builtin"); + build.flag("-fvisibility=hidden"); + build.flag("-ffreestanding"); // Avoid the following warning appearing once **per file**: // clang: warning: optimization flag '-fomit-frame-pointer' is not supported for target 'armv7' [-Wignored-optimization-argument] // @@ -266,17 +269,17 @@ mod c { // `check_cxx_compiler_flag(-fomit-frame-pointer COMPILER_RT_HAS_FOMIT_FRAME_POINTER_FLAG)` // // in https://github.com/rust-lang/compiler-rt/blob/c8fbcb3/cmake/config-ix.cmake#L19. - cfg.flag_if_supported("-fomit-frame-pointer"); - cfg.define("VISIBILITY_HIDDEN", None); + build.flag_if_supported("-fomit-frame-pointer"); + build.define("VISIBILITY_HIDDEN", None); - if let "aarch64" | "arm64ec" = target.arch.as_str() { + if let "aarch64" | "arm64ec" = cfg.target_arch.as_str() { // FIXME(llvm20): Older GCCs on A64 fail to build with // -Werror=implicit-function-declaration due to a compiler-rt bug. // With a newer LLVM we should be able to enable the flag everywhere. // https://github.com/llvm/llvm-project/commit/8aa9d6206ce55bdaaf422839c351fbd63f033b89 } else { // Avoid implicitly creating references to undefined functions - cfg.flag("-Werror=implicit-function-declaration"); + build.flag("-Werror=implicit-function-declaration"); } } @@ -285,14 +288,14 @@ mod c { // at odds with compiling with `-ffreestanding`, as the header // may be incompatible or not present. Create a minimal stub // header to use instead. - if target.os == "uefi" { + if cfg.target_os == "uefi" { let out_dir = PathBuf::from(env::var("OUT_DIR").unwrap()); let include_dir = out_dir.join("include"); if !include_dir.exists() { fs::create_dir(&include_dir).unwrap(); } fs::write(include_dir.join("stdlib.h"), "#include ").unwrap(); - cfg.flag(&format!("-I{}", include_dir.to_str().unwrap())); + build.flag(&format!("-I{}", include_dir.to_str().unwrap())); } let mut sources = Sources::new(); @@ -330,7 +333,7 @@ mod c { // On iOS and 32-bit OSX these are all just empty intrinsics, no need to // include them. - if target.vendor != "apple" || target.arch != "x86" { + if cfg.target_vendor != "apple" || cfg.target_arch != "x86" { sources.extend(&[ ("__absvti2", "absvti2.c"), ("__addvti3", "addvti3.c"), @@ -349,7 +352,7 @@ mod c { } } - if target.vendor == "apple" { + if cfg.target_vendor == "apple" { sources.extend(&[ ("atomic_flag_clear", "atomic_flag_clear.c"), ("atomic_flag_clear_explicit", "atomic_flag_clear_explicit.c"), @@ -363,8 +366,8 @@ mod c { ]); } - if target.env != "msvc" { - if target.arch == "x86" { + if cfg.target_env != "msvc" { + if cfg.target_arch == "x86" { sources.extend(&[ ("__ashldi3", "i386/ashldi3.S"), ("__ashrdi3", "i386/ashrdi3.S"), @@ -378,7 +381,7 @@ mod c { } } - if target.arch == "arm" && target.vendor != "apple" && target.env != "msvc" { + if cfg.target_arch == "arm" && cfg.target_vendor != "apple" && cfg.target_env != "msvc" { sources.extend(&[ ("__aeabi_div0", "arm/aeabi_div0.c"), ("__aeabi_drsub", "arm/aeabi_drsub.c"), @@ -398,7 +401,7 @@ mod c { ("__umodsi3", "arm/umodsi3.S"), ]); - if target.os == "freebsd" { + if cfg.target_os == "freebsd" { sources.extend(&[("__clear_cache", "clear_cache.c")]); } @@ -470,31 +473,36 @@ mod c { ]); } - if (target.arch == "aarch64" || target.arch == "arm64ec") && consider_float_intrinsics { + if (cfg.target_arch == "aarch64" || cfg.target_arch == "arm64ec") + && consider_float_intrinsics + { sources.extend(&[ ("__fe_getround", "fp_mode.c"), ("__fe_raise_inexact", "fp_mode.c"), ]); - if target.os != "windows" && target.os != "cygwin" { + if cfg.target_os != "windows" && cfg.target_os != "cygwin" { sources.extend(&[("__multc3", "multc3.c")]); } } - if target.arch == "mips" || target.arch == "riscv32" || target.arch == "riscv64" { + if cfg.target_arch == "mips" || cfg.target_arch == "riscv32" || cfg.target_arch == "riscv64" + { sources.extend(&[("__bswapsi2", "bswapsi2.c")]); } - if target.arch == "mips64" { + if cfg.target_arch == "mips64" { sources.extend(&[("__fe_getround", "fp_mode.c")]); } - if target.arch == "loongarch64" { + if cfg.target_arch == "loongarch64" { sources.extend(&[("__fe_getround", "fp_mode.c")]); } // Remove the assembly implementations that won't compile for the target - if llvm_target[0] == "thumbv6m" || llvm_target[0] == "thumbv8m.base" || target.os == "uefi" + if llvm_target[0] == "thumbv6m" + || llvm_target[0] == "thumbv8m.base" + || cfg.target_os == "uefi" { let mut to_remove = Vec::new(); for (k, v) in sources.map.iter() { @@ -510,19 +518,19 @@ mod c { } // Android and Cygwin uses emulated TLS so we need a runtime support function. - if target.os == "android" || target.os == "cygwin" { + if cfg.target_os == "android" || cfg.target_os == "cygwin" { sources.extend(&[("__emutls_get_address", "emutls.c")]); } // Work around a bug in the NDK headers (fixed in // https://r.android.com/2038949 which will be released in a future // NDK version) by providing a definition of LONG_BIT. - if target.os == "android" { - cfg.define("LONG_BIT", "(8 * sizeof(long))"); + if cfg.target_os == "android" { + build.define("LONG_BIT", "(8 * sizeof(long))"); } // OpenHarmony also uses emulated TLS. - if target.env == "ohos" { + if cfg.target_env == "ohos" { sources.extend(&[("__emutls_get_address", "emutls.c")]); } @@ -554,16 +562,16 @@ mod c { // Support deterministic builds by remapping the __FILE__ prefix if the // compiler supports it. This fixes the nondeterminism caused by the // use of that macro in lib/builtins/int_util.h in compiler-rt. - cfg.flag_if_supported(&format!("-ffile-prefix-map={}=.", root.display())); + build.flag_if_supported(&format!("-ffile-prefix-map={}=.", root.display())); // Include out-of-line atomics for aarch64, which are all generated by supplying different // sets of flags to the same source file. // Note: Out-of-line aarch64 atomics are not supported by the msvc toolchain (#430) and // on uefi. let src_dir = root.join("lib/builtins"); - if target.arch == "aarch64" && target.env != "msvc" && target.os != "uefi" { + if cfg.target_arch == "aarch64" && cfg.target_env != "msvc" && cfg.target_os != "uefi" { // See below for why we're building these as separate libraries. - build_aarch64_out_of_line_atomics_libraries(&src_dir, cfg, link_against_prebuilt_rt); + build_aarch64_out_of_line_atomics_libraries(&src_dir, build, link_against_prebuilt_rt); // Some run-time CPU feature detection is necessary, as well. let cpu_model_src = if src_dir.join("cpu_model.c").exists() { @@ -578,7 +586,7 @@ mod c { for (sym, src) in sources.map.iter() { let src = src_dir.join(src); if !link_against_prebuilt_rt && added_sources.insert(src.clone()) { - cfg.file(&src); + build.file(&src); println!("cargo:rerun-if-changed={}", src.display()); } println!("cargo:rustc-cfg={}=\"optimized-c\"", sym); @@ -602,7 +610,7 @@ mod c { ); } } else { - cfg.compile("libcompiler-rt.a"); + build.compile("libcompiler-rt.a"); } } diff --git a/library/compiler-builtins/compiler-builtins/configure.rs b/library/compiler-builtins/compiler-builtins/configure.rs index 4dcb933834421..2da91558ced07 100644 --- a/library/compiler-builtins/compiler-builtins/configure.rs +++ b/library/compiler-builtins/compiler-builtins/configure.rs @@ -10,36 +10,30 @@ static VERBOSE_BUILD: AtomicBool = AtomicBool::new(false); #[derive(Debug)] #[allow(dead_code)] -pub struct Target { - pub triple: String, - pub triple_split: Vec, - pub opt_level: String, +pub struct Config { pub cargo_features: Vec, - pub os: String, - pub arch: String, - pub vendor: String, - pub env: String, - pub pointer_width: u8, - pub little_endian: bool, - pub features: Vec, + pub opt_level: String, pub reliable_f128: bool, pub reliable_f16: bool, + pub target_arch: String, + pub target_env: String, + pub target_features: Vec, + pub target_os: String, + pub target_pointer_width: u8, + pub target_triple: String, + pub target_triple_split: Vec, + pub target_vendor: String, } -impl Target { +impl Config { pub fn from_env() -> Self { println!("cargo:cargo::rerun-if-env-changed=LIBM_BUILD_VERBOSE"); if env_flag("LIBM_BUILD_VERBOSE") { VERBOSE_BUILD.store(true, Relaxed); } - let triple = env::var("TARGET").unwrap(); - let triple_split = triple.split('-').map(ToOwned::to_owned).collect(); - let little_endian = match env::var("CARGO_CFG_TARGET_ENDIAN").unwrap().as_str() { - "little" => true, - "big" => false, - x => panic!("unknown endian {x}"), - }; + let target_triple = env::var("TARGET").unwrap(); + let target_triple_split = target_triple.split('-').map(ToOwned::to_owned).collect(); let cargo_features = env::vars() .filter_map(|(name, _value)| name.strip_prefix("CARGO_FEATURE_").map(ToOwned::to_owned)) .map(|s| s.to_lowercase().replace("_", "-")) @@ -51,20 +45,19 @@ impl Target { } Self { - triple, - triple_split, - os: env::var("CARGO_CFG_TARGET_OS").unwrap(), + target_triple, + target_triple_split, + target_os: env::var("CARGO_CFG_TARGET_OS").unwrap(), opt_level: env::var("OPT_LEVEL").unwrap(), cargo_features, - arch: env::var("CARGO_CFG_TARGET_ARCH").unwrap(), - vendor: env::var("CARGO_CFG_TARGET_VENDOR").unwrap(), - env: env::var("CARGO_CFG_TARGET_ENV").unwrap(), - pointer_width: env::var("CARGO_CFG_TARGET_POINTER_WIDTH") + target_arch: env::var("CARGO_CFG_TARGET_ARCH").unwrap(), + target_vendor: env::var("CARGO_CFG_TARGET_VENDOR").unwrap(), + target_env: env::var("CARGO_CFG_TARGET_ENV").unwrap(), + target_pointer_width: env::var("CARGO_CFG_TARGET_POINTER_WIDTH") .unwrap() .parse() .unwrap(), - little_endian, - features: env::var("CARGO_CFG_TARGET_FEATURE") + target_features: env::var("CARGO_CFG_TARGET_FEATURE") .unwrap_or_default() .split(",") .map(ToOwned::to_owned) @@ -77,24 +70,26 @@ impl Target { } #[allow(dead_code)] - pub fn has_feature(&self, feature: &str) -> bool { - self.features.iter().any(|f| f == feature) + pub fn has_target_feature(&self, feature: &str) -> bool { + self.target_features.iter().any(|f| f == feature) } } -pub fn configure_aliases(target: &Target) { +pub fn configure_aliases(cfg: &Config) { + let triple_split = &cfg.target_triple_split; + // To compile builtins-test-intrinsics for thumb targets, where there is no libc - let thumb = target.triple_split[0].starts_with("thumb"); + let thumb = triple_split[0].starts_with("thumb"); set_cfg("thumb", thumb); // compiler-rt `cfg`s away some intrinsics for thumbv6m and thumbv8m.base because // these targets do not have full Thumb-2 support but only original Thumb-1. // We have to cfg our code accordingly. - let thumb_1 = target.triple_split[0] == "thumbv6m" || target.triple_split[0] == "thumbv8m.base"; + let thumb_1 = triple_split[0] == "thumbv6m" || triple_split[0] == "thumbv8m.base"; set_cfg("thumb_1", thumb_1); // Shorthand to detect i586 targets - let x86_no_sse2 = target.arch == "x86" && !target.features.iter().any(|f| f == "sse2"); + let x86_no_sse2 = cfg.target_arch == "x86" && !cfg.target_features.iter().any(|f| f == "sse2"); set_cfg("x86_no_sse2", x86_no_sse2); /* Not all backends support `f16` and `f128` to the same level on all architectures, so we @@ -104,8 +99,8 @@ pub fn configure_aliases(target: &Target) { * * https://github.com/rust-lang/rustc_codegen_cranelift/blob/c713ffab3c6e28ab4b4dd4e392330f786ea657ad/src/lib.rs#L196-L226 */ - set_cfg("f16_enabled", target.reliable_f16); - set_cfg("f128_enabled", target.reliable_f128); + set_cfg("f16_enabled", cfg.reliable_f16); + set_cfg("f128_enabled", cfg.reliable_f128); } pub fn set_cfg(name: &str, set: bool) { From f5ca8e59fbf1f3caf0c9cc0dfbca0c969e2be6fe Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Thu, 2 Apr 2026 01:21:20 -0400 Subject: [PATCH 098/183] build: Use a single configure file for all libraries Some libraries already share a lot, but there is still some repeated or scattered config. Centralize this all in `libm/configure.rs`. --- .../builtins-test-intrinsics/build.rs | 14 +- .../compiler-builtins/builtins-test/build.rs | 17 +-- .../compiler-builtins/build.rs | 44 +----- .../compiler-builtins/configure.rs | 125 ----------------- .../compiler-builtins/crates/util/build.rs | 8 +- .../compiler-builtins/libm-test/Cargo.toml | 6 - library/compiler-builtins/libm-test/build.rs | 7 +- library/compiler-builtins/libm/build.rs | 12 +- library/compiler-builtins/libm/configure.rs | 129 ++++++++++++------ 9 files changed, 120 insertions(+), 242 deletions(-) delete mode 100644 library/compiler-builtins/compiler-builtins/configure.rs diff --git a/library/compiler-builtins/builtins-test-intrinsics/build.rs b/library/compiler-builtins/builtins-test-intrinsics/build.rs index 4dcad9e459917..c1ab650a6e82a 100644 --- a/library/compiler-builtins/builtins-test-intrinsics/build.rs +++ b/library/compiler-builtins/builtins-test-intrinsics/build.rs @@ -1,10 +1,10 @@ -mod builtins_configure { - include!("../compiler-builtins/configure.rs"); -} +#[path = "../libm/configure.rs"] +mod configure; -fn main() { - println!("cargo::rerun-if-changed=../configure.rs"); +use configure::{Config, Library}; - let cfg = builtins_configure::Config::from_env(); - builtins_configure::configure_aliases(&cfg); +fn main() { + println!("cargo::rerun-if-changed=../libm/configure.rs"); + let cfg = Config::from_env(Library::BuiltinsTestIntrinsics); + configure::emit(&cfg); } diff --git a/library/compiler-builtins/builtins-test/build.rs b/library/compiler-builtins/builtins-test/build.rs index af688c00cff26..133186bc7f57d 100644 --- a/library/compiler-builtins/builtins-test/build.rs +++ b/library/compiler-builtins/builtins-test/build.rs @@ -1,8 +1,9 @@ +#[path = "../libm/configure.rs"] +mod configure; + use std::collections::HashSet; -mod builtins_configure { - include!("../compiler-builtins/configure.rs"); -} +use configure::{Config, Library, set_cfg}; /// Features to enable #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] @@ -45,9 +46,11 @@ impl SetCfg { } fn main() { - println!("cargo::rerun-if-changed=../configure.rs"); + println!("cargo::rerun-if-changed=../libm/configure.rs"); + + let cfg = Config::from_env(Library::BuiltinsTest); + configure::emit(&cfg); - let cfg = builtins_configure::Config::from_env(); let mut to_set = HashSet::new(); // These platforms do not have f128 symbols available in their system libraries, so @@ -113,8 +116,6 @@ fn main() { ); for cfg in SetCfg::ALL { - builtins_configure::set_cfg(cfg.name(), to_set.contains(cfg)); + set_cfg(cfg.name(), to_set.contains(cfg)); } - - builtins_configure::configure_aliases(&cfg); } diff --git a/library/compiler-builtins/compiler-builtins/build.rs b/library/compiler-builtins/compiler-builtins/build.rs index c86d3e588e41c..c85ef306aeab9 100644 --- a/library/compiler-builtins/compiler-builtins/build.rs +++ b/library/compiler-builtins/compiler-builtins/build.rs @@ -1,21 +1,19 @@ +#[path = "../libm/configure.rs"] mod configure; use std::env; -use configure::{Config, configure_aliases, set_cfg}; +use configure::{Config, Library, set_cfg}; fn main() { println!("cargo::rerun-if-changed=build.rs"); - println!("cargo::rerun-if-changed=configure.rs"); - - let cfg = Config::from_env(); - let cwd = env::current_dir().unwrap(); + println!("cargo::rerun-if-changed=../libm/configure.rs"); + let cfg = Config::from_env(Library::CompilerBuiltins); + configure::emit(&cfg); configure_check_cfg(); - configure_aliases(&cfg); - - configure_libm(&cfg); + let cwd = env::current_dir().unwrap(); println!("cargo:compiler-rt={}", cwd.join("compiler-rt").display()); println!("cargo::rustc-check-cfg=cfg(kernel_user_helpers)"); @@ -80,32 +78,6 @@ fn main() { set_cfg("kernel_user_helpers", kernel_user_helpers); } -/// Run configuration for `libm` since it is included directly. -/// -/// Much of this is copied from `libm/configure.rs`. -fn configure_libm(cfg: &Config) { - println!("cargo:rustc-check-cfg=cfg(feature, values(\"unstable-public-internals\"))"); - - // Always use intrinsics - set_cfg("intrinsics_enabled", true); - - let opt = !matches!(cfg.opt_level.as_str(), "0" | "1"); - set_cfg("optimizations_enabled", opt); - - println!( - "cargo:rustc-env=CFG_CARGO_FEATURES={:?}", - cfg.cargo_features - ); - println!("cargo:rustc-env=CFG_OPT_LEVEL={}", cfg.opt_level); - println!( - "cargo:rustc-env=CFG_TARGET_FEATURES={:?}", - cfg.target_features - ); - - // Activate libm's unstable features to make full use of Nightly. - println!("cargo:rustc-cfg=feature=\"unstable-intrinsics\""); -} - /// Emit directives for features we expect to support that aren't in `Cargo.toml`. /// /// These are mostly cfg elements emitted by this `build.rs`. @@ -165,10 +137,6 @@ fn configure_check_cfg() { // Rustc is unaware of sparc target features, but this does show up from // `rustc --print target-features --target sparc64-unknown-linux-gnu`. println!("cargo::rustc-check-cfg=cfg(target_feature, values(\"vis3\"))"); - - // FIXME: these come from libm and should be changed there - println!("cargo::rustc-check-cfg=cfg(feature, values(\"checked\"))"); - println!("cargo::rustc-check-cfg=cfg(assert_no_panic)"); } #[cfg(feature = "c")] diff --git a/library/compiler-builtins/compiler-builtins/configure.rs b/library/compiler-builtins/compiler-builtins/configure.rs deleted file mode 100644 index 2da91558ced07..0000000000000 --- a/library/compiler-builtins/compiler-builtins/configure.rs +++ /dev/null @@ -1,125 +0,0 @@ -// Configuration that is shared between `compiler_builtins` and `builtins_test`. - -use std::env::{self, VarError}; -use std::str; -use std::sync::atomic::AtomicBool; -use std::sync::atomic::Ordering::Relaxed; - -/// Read from env, print more debug output via `cargo:warning` if set. -static VERBOSE_BUILD: AtomicBool = AtomicBool::new(false); - -#[derive(Debug)] -#[allow(dead_code)] -pub struct Config { - pub cargo_features: Vec, - pub opt_level: String, - pub reliable_f128: bool, - pub reliable_f16: bool, - pub target_arch: String, - pub target_env: String, - pub target_features: Vec, - pub target_os: String, - pub target_pointer_width: u8, - pub target_triple: String, - pub target_triple_split: Vec, - pub target_vendor: String, -} - -impl Config { - pub fn from_env() -> Self { - println!("cargo:cargo::rerun-if-env-changed=LIBM_BUILD_VERBOSE"); - if env_flag("LIBM_BUILD_VERBOSE") { - VERBOSE_BUILD.store(true, Relaxed); - } - - let target_triple = env::var("TARGET").unwrap(); - let target_triple_split = target_triple.split('-').map(ToOwned::to_owned).collect(); - let cargo_features = env::vars() - .filter_map(|(name, _value)| name.strip_prefix("CARGO_FEATURE_").map(ToOwned::to_owned)) - .map(|s| s.to_lowercase().replace("_", "-")) - .collect(); - if VERBOSE_BUILD.load(Relaxed) { - for feature in &cargo_features { - println!("cargo:warning=feature `{feature}` enabled"); - } - } - - Self { - target_triple, - target_triple_split, - target_os: env::var("CARGO_CFG_TARGET_OS").unwrap(), - opt_level: env::var("OPT_LEVEL").unwrap(), - cargo_features, - target_arch: env::var("CARGO_CFG_TARGET_ARCH").unwrap(), - target_vendor: env::var("CARGO_CFG_TARGET_VENDOR").unwrap(), - target_env: env::var("CARGO_CFG_TARGET_ENV").unwrap(), - target_pointer_width: env::var("CARGO_CFG_TARGET_POINTER_WIDTH") - .unwrap() - .parse() - .unwrap(), - target_features: env::var("CARGO_CFG_TARGET_FEATURE") - .unwrap_or_default() - .split(",") - .map(ToOwned::to_owned) - .collect(), - // Note that these are unstable options, so only show up with the nightly compiler or - // with `RUSTC_BOOTSTRAP=1` (which is required to use the types anyway). - reliable_f128: env::var_os("CARGO_CFG_TARGET_HAS_RELIABLE_F128").is_some(), - reliable_f16: env::var_os("CARGO_CFG_TARGET_HAS_RELIABLE_F16").is_some(), - } - } - - #[allow(dead_code)] - pub fn has_target_feature(&self, feature: &str) -> bool { - self.target_features.iter().any(|f| f == feature) - } -} - -pub fn configure_aliases(cfg: &Config) { - let triple_split = &cfg.target_triple_split; - - // To compile builtins-test-intrinsics for thumb targets, where there is no libc - let thumb = triple_split[0].starts_with("thumb"); - set_cfg("thumb", thumb); - - // compiler-rt `cfg`s away some intrinsics for thumbv6m and thumbv8m.base because - // these targets do not have full Thumb-2 support but only original Thumb-1. - // We have to cfg our code accordingly. - let thumb_1 = triple_split[0] == "thumbv6m" || triple_split[0] == "thumbv8m.base"; - set_cfg("thumb_1", thumb_1); - - // Shorthand to detect i586 targets - let x86_no_sse2 = cfg.target_arch == "x86" && !cfg.target_features.iter().any(|f| f == "sse2"); - set_cfg("x86_no_sse2", x86_no_sse2); - - /* Not all backends support `f16` and `f128` to the same level on all architectures, so we - * need to disable things if the compiler may crash. See configuration at: - * * https://github.com/rust-lang/rust/blob/c65dccabacdfd6c8a7f7439eba13422fdd89b91e/compiler/rustc_codegen_llvm/src/llvm_util.rs#L367-L432 - * * https://github.com/rust-lang/rustc_codegen_gcc/blob/4b5c44b14166083eef8d71f15f5ea1f53fc976a0/src/lib.rs#L496-L507 - * * https://github.com/rust-lang/rustc_codegen_cranelift/blob/c713ffab3c6e28ab4b4dd4e392330f786ea657ad/src/lib.rs#L196-L226 - */ - - set_cfg("f16_enabled", cfg.reliable_f16); - set_cfg("f128_enabled", cfg.reliable_f128); -} - -pub fn set_cfg(name: &str, set: bool) { - println!("cargo:rustc-check-cfg=cfg({name})"); - if !set { - return; - } - if VERBOSE_BUILD.load(Relaxed) { - println!("cargo:warning=setting config `{name}`"); - } - println!("cargo:rustc-cfg={name}"); -} - -/// Return true if the env is set to a value other than `0`. -pub fn env_flag(key: &str) -> bool { - match env::var(key) { - Ok(x) if x == "0" => false, - Err(VarError::NotPresent) => false, - Err(VarError::NotUnicode(_)) => panic!("non-unicode var for `{key}`"), - Ok(_) => true, - } -} diff --git a/library/compiler-builtins/crates/util/build.rs b/library/compiler-builtins/crates/util/build.rs index a1be4127527ae..f7ed72addee10 100644 --- a/library/compiler-builtins/crates/util/build.rs +++ b/library/compiler-builtins/crates/util/build.rs @@ -1,10 +1,10 @@ -#![allow(unexpected_cfgs)] - #[path = "../../libm/configure.rs"] mod configure; +use configure::{Config, Library}; + fn main() { println!("cargo:rerun-if-changed=../../libm/configure.rs"); - let cfg = configure::Config::from_env(); - configure::emit_libm_config(&cfg); + let cfg = Config::from_env(Library::Util); + configure::emit(&cfg); } diff --git a/library/compiler-builtins/libm-test/Cargo.toml b/library/compiler-builtins/libm-test/Cargo.toml index 271c8a599d81b..5014fb0008611 100644 --- a/library/compiler-builtins/libm-test/Cargo.toml +++ b/library/compiler-builtins/libm-test/Cargo.toml @@ -76,9 +76,3 @@ required-features = ["walltime"] # `z` so these tests get run last. name = "z_extensive" harness = false - -[lints.rust] -# Values from the chared config.rs used by `libm` but not the test crate -unexpected_cfgs = { level = "warn", check-cfg = [ - 'cfg(feature, values("arch", "unstable-intrinsics"))', -] } diff --git a/library/compiler-builtins/libm-test/build.rs b/library/compiler-builtins/libm-test/build.rs index 510ba842f10ab..fa7db8ed63e3e 100644 --- a/library/compiler-builtins/libm-test/build.rs +++ b/library/compiler-builtins/libm-test/build.rs @@ -1,9 +1,10 @@ #[path = "../libm/configure.rs"] mod configure; -use configure::Config; + +use configure::{Config, Library}; fn main() { println!("cargo:rerun-if-changed=../libm/configure.rs"); - let cfg = Config::from_env(); - configure::emit_test_config(&cfg); + let cfg = Config::from_env(Library::LibmTest); + configure::emit(&cfg); } diff --git a/library/compiler-builtins/libm/build.rs b/library/compiler-builtins/libm/build.rs index 054fa4b74ef76..584e6a25da270 100644 --- a/library/compiler-builtins/libm/build.rs +++ b/library/compiler-builtins/libm/build.rs @@ -1,17 +1,11 @@ mod configure; -use configure::{emit_libm_config, env_flag, set_cfg}; +use configure::{Config, Library}; fn main() { - let cfg = configure::Config::from_env(); - println!("cargo:rerun-if-changed=build.rs"); println!("cargo:rerun-if-changed=configure.rs"); - println!("cargo:rustc-check-cfg=cfg(assert_no_panic)"); - - // If set, enable `no-panic`. Requires LTO (`release-opt` profile). - let no_panic = env_flag("ENSURE_NO_PANIC"); - set_cfg("assert_no_panic", no_panic); - emit_libm_config(&cfg); + let cfg = Config::from_env(Library::Libm); + configure::emit(&cfg); } diff --git a/library/compiler-builtins/libm/configure.rs b/library/compiler-builtins/libm/configure.rs index 618a994de0da9..ec4e46c391042 100644 --- a/library/compiler-builtins/libm/configure.rs +++ b/library/compiler-builtins/libm/configure.rs @@ -1,4 +1,4 @@ -// Configuration shared with both libm and libm-test +//! Common configuration shared by multiple crates in the workspace. use std::env::{self, VarError}; use std::path::PathBuf; @@ -11,11 +11,13 @@ static VERBOSE_BUILD: AtomicBool = AtomicBool::new(false); #[derive(Debug)] #[allow(dead_code)] pub struct Config { + pub library: Library, pub manifest_dir: PathBuf, pub out_dir: PathBuf, pub opt_level: String, pub cargo_features: Vec, pub target_triple: String, + pub target_triple_split: Vec, pub target_arch: String, pub target_env: String, pub target_families: Vec, @@ -28,13 +30,14 @@ pub struct Config { } impl Config { - pub fn from_env() -> Self { - println!("cargo:cargo::rerun-if-env-changed=LIBM_BUILD_VERBOSE"); + pub fn from_env(library: Library) -> Self { + println!("cargo:rerun-if-env-changed=LIBM_BUILD_VERBOSE"); if env_flag("LIBM_BUILD_VERBOSE") { VERBOSE_BUILD.store(true, Relaxed); } let target_triple = env::var("TARGET").unwrap(); + let target_triple_split = target_triple.split('-').map(ToOwned::to_owned).collect(); let target_families = env::var("CARGO_CFG_TARGET_FAMILY") .map(|feats| feats.split(',').map(ToOwned::to_owned).collect()) .unwrap_or_default(); @@ -52,7 +55,9 @@ impl Config { } Self { + library, target_triple, + target_triple_split, manifest_dir: PathBuf::from(env::var("CARGO_MANIFEST_DIR").unwrap()), out_dir: PathBuf::from(env::var("OUT_DIR").unwrap()), opt_level: env::var("OPT_LEVEL").unwrap(), @@ -70,50 +75,98 @@ impl Config { reliable_f16: env::var_os("CARGO_CFG_TARGET_HAS_RELIABLE_F16").is_some(), } } -} -/// Libm gets most config options made available. -#[allow(dead_code)] -pub fn emit_libm_config(cfg: &Config) { - emit_intrinsics_cfg(); - emit_optimization_cfg(cfg); - emit_cfg_shorthands(cfg); - emit_cfg_env(cfg); - emit_f16_f128_cfg(cfg); + #[allow(dead_code)] + pub fn has_target_feature(&self, feature: &str) -> bool { + self.target_features.iter().any(|f| f == feature) + } } -/// Tests don't need most feature-related config. +/// The library that is setting this configuration #[allow(dead_code)] -pub fn emit_test_config(cfg: &Config) { - emit_optimization_cfg(cfg); - emit_cfg_shorthands(cfg); - emit_cfg_env(cfg); - emit_f16_f128_cfg(cfg); +#[derive(Debug)] +pub enum Library { + BuiltinsTest, + BuiltinsTestIntrinsics, + CompilerBuiltins, + Libm, + LibmTest, + Util, } -/// Simplify the feature logic for enabling intrinsics so code only needs to use -/// `cfg(intrinsics_enabled)`. -fn emit_intrinsics_cfg() { - // Disabled by default; `unstable-intrinsics` enables again; `force-soft-floats` overrides - // to disable. - let intrinsics = cfg!(feature = "unstable-intrinsics") && cfg!(feature = "arch"); - set_cfg("intrinsics_enabled", intrinsics); -} +#[allow(unexpected_cfgs)] // Not all crates use all these features +pub fn emit(cfg: &Config) { + let split = &cfg.target_triple_split; + + let unstable_float = cfg!(feature = "unstable-float"); -/// Some tests are extremely slow. Emit a config option based on optimization level. -fn emit_optimization_cfg(cfg: &Config) { + // Intrinsics may include `core::arch` use, so also gate it under `arch`. + let intrinsics_enabled = cfg!(feature = "unstable-intrinsics") && cfg!(feature = "arch"); + + // Some tests are extremely slow. Emit a config option based on optimization level. let opt = !matches!(cfg.opt_level.as_str(), "0" | "1"); - set_cfg("optimizations_enabled", opt); -} -/// Provide an alias for common longer config combinations. -fn emit_cfg_shorthands(cfg: &Config) { + // To compile builtins-test-intrinsics for thumb targets, where there is no libc + let thumb = split[0].starts_with("thumb"); + + // compiler-rt `cfg`s away some intrinsics for thumbv6m and thumbv8m.base because + // these targets do not have full Thumb-2 support but only original Thumb-1. + // We have to cfg our code accordingly. + let thumb_1 = split[0] == "thumbv6m" || split[0] == "thumbv8m.base"; + // Shorthand to detect i586 targets let x86_no_sse2 = cfg.target_arch == "x86" && !cfg.target_features.iter().any(|f| f == "sse2"); + + // If set, enable `no-panic` for `libm`. Requires LTO (`release-opt` profile). + let assert_no_panic = env_flag("ENSURE_NO_PANIC"); + + // Arch shorthand config is used in most crates. + set_cfg("thumb", thumb); + set_cfg("thumb_1", thumb_1); set_cfg("x86_no_sse2", x86_no_sse2); + + match cfg.library { + Library::CompilerBuiltins => { + // libm config. Intrinsics are always enabled when a part of c-b. + set_cfg("assert_no_panic", assert_no_panic); + set_cfg("intrinsics_enabled", true); + set_cfg("optimizations_enabled", opt); + + // Not all backends support `f16` and `f128` to the same level on all architectures, + // so we need to disable things if the compiler may crash. See configuration at: + // * https://github.com/rust-lang/rust/blob/c65dccabacdfd6c8a7f7439eba13422fdd89b91e/compiler/rustc_codegen_llvm/src/llvm_util.rs#L367-L432 + // * https://github.com/rust-lang/rustc_codegen_gcc/blob/4b5c44b14166083eef8d71f15f5ea1f53fc976a0/src/lib.rs#L496-L507 + // * https://github.com/rust-lang/rustc_codegen_cranelift/blob/c713ffab3c6e28ab4b4dd4e392330f786ea657ad/src/lib.rs#L196-L226 + set_cfg("f16_enabled", cfg.reliable_f16); + set_cfg("f128_enabled", cfg.reliable_f128); + } + Library::BuiltinsTest => { + set_cfg("f16_enabled", cfg.reliable_f16); + set_cfg("f128_enabled", cfg.reliable_f128); + } + Library::BuiltinsTestIntrinsics => { + set_cfg("f16_enabled", cfg.reliable_f16); + set_cfg("f128_enabled", cfg.reliable_f128); + } + Library::Libm | Library::Util => { + set_cfg("assert_no_panic", assert_no_panic); + set_cfg("intrinsics_enabled", intrinsics_enabled); + set_cfg("optimizations_enabled", opt); + + set_cfg("f16_enabled", unstable_float && cfg.reliable_f16); + set_cfg("f128_enabled", unstable_float && cfg.reliable_f128); + } + Library::LibmTest => { + set_cfg("optimizations_enabled", opt); + emit_cfg_env(cfg); + + set_cfg("f16_enabled", unstable_float && cfg.reliable_f16); + set_cfg("f128_enabled", unstable_float && cfg.reliable_f128); + } + } } -/// Reemit config that we make use of for test logging. +/// Re-emit config that we make use of for test logging. fn emit_cfg_env(cfg: &Config) { println!( "cargo:rustc-env=CFG_CARGO_FEATURES={:?}", @@ -126,15 +179,7 @@ fn emit_cfg_env(cfg: &Config) { ); } -/// Configure whether or not `f16` and `f128` support should be enabled. -fn emit_f16_f128_cfg(cfg: &Config) { - // `unstable-float` enables these features. See the compiler-builtins file for their - // meaning. - let unstable_float = cfg!(feature = "unstable-float"); - set_cfg("f16_enabled", unstable_float && cfg.reliable_f16); - set_cfg("f128_enabled", unstable_float && cfg.reliable_f128); -} - +/// Emit a check-cfg directive and enable the cfg if `set` is `true`. pub fn set_cfg(name: &str, set: bool) { println!("cargo:rustc-check-cfg=cfg({name})"); if !set { From 2df972607eedc8ddb9bf50932e3d3beb113e3aaa Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Tue, 7 Apr 2026 07:07:59 -0500 Subject: [PATCH 099/183] build: Fix c-b builds always being marked dirty --- .../compiler-builtins/compiler-builtins/build.rs | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/library/compiler-builtins/compiler-builtins/build.rs b/library/compiler-builtins/compiler-builtins/build.rs index c85ef306aeab9..d8019277d3ff4 100644 --- a/library/compiler-builtins/compiler-builtins/build.rs +++ b/library/compiler-builtins/compiler-builtins/build.rs @@ -6,10 +6,19 @@ use std::env; use configure::{Config, Library, set_cfg}; fn main() { - println!("cargo::rerun-if-changed=build.rs"); + let cfg = Config::from_env(Library::CompilerBuiltins); + + // Work around building as part of `builtins-shim`: if only `build.rs` is used, Cargo always + // considers the build dirty because `builtins-shim/build.rs` does not exist. If only + // `../c-b/build.rs` is used, the same may happen if not built in the workspace. + if cfg.manifest_dir.file_name().unwrap() == "builtins-shim" { + println!("cargo::rerun-if-changed=../compiler-builtins/build.rs"); + } else { + println!("cargo::rerun-if-changed=build.rs"); + } + println!("cargo::rerun-if-changed=../libm/configure.rs"); - let cfg = Config::from_env(Library::CompilerBuiltins); configure::emit(&cfg); configure_check_cfg(); From cea20e0e61a93be1fb77e44fbb38e062de6837e3 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Tue, 7 Apr 2026 07:12:33 -0500 Subject: [PATCH 100/183] ci: Increase the timeout for benchmark jobs to 30 minutes The i686 job has sometimes hit the existing 20 minute limit when things take an extra long time to download. --- library/compiler-builtins/.github/workflows/main.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/.github/workflows/main.yaml b/library/compiler-builtins/.github/workflows/main.yaml index 83eac57fd9452..39aab42a3950a 100644 --- a/library/compiler-builtins/.github/workflows/main.yaml +++ b/library/compiler-builtins/.github/workflows/main.yaml @@ -280,7 +280,7 @@ jobs: benchmarks: name: Benchmarks - timeout-minutes: 20 + timeout-minutes: 30 strategy: fail-fast: false matrix: From 5fd302043b446cc1545d3b86270776c244e5376c Mon Sep 17 00:00:00 2001 From: The rustc-josh-sync Cronjob Bot Date: Thu, 9 Apr 2026 04:56:10 +0000 Subject: [PATCH 101/183] Prepare for merging from rust-lang/rust This updates the rust-version file to d0442e2800d356ae282ddcdbe0eff8798fe648b6. --- library/compiler-builtins/rust-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/rust-version b/library/compiler-builtins/rust-version index e98704ad335bd..8ce8152f91161 100644 --- a/library/compiler-builtins/rust-version +++ b/library/compiler-builtins/rust-version @@ -1 +1 @@ -0e95a0f4c677002a5d4ac5bc59d97885e6f51f71 +d0442e2800d356ae282ddcdbe0eff8798fe648b6 From 06ea8566a17e0aa027d391dae756939cd08fc642 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Fri, 20 Mar 2026 18:25:24 -0400 Subject: [PATCH 102/183] libm: Add basic tests for u256::shl Duplicate the shr test style to have a simple check for edge cases. --- .../libm/src/math/support/big/tests.rs | 168 +++++++++++++++++- 1 file changed, 167 insertions(+), 1 deletion(-) diff --git a/library/compiler-builtins/libm/src/math/support/big/tests.rs b/library/compiler-builtins/libm/src/math/support/big/tests.rs index 133e3739314d0..4397b4478bb8d 100644 --- a/library/compiler-builtins/libm/src/math/support/big/tests.rs +++ b/library/compiler-builtins/libm/src/math/support/big/tests.rs @@ -1,7 +1,7 @@ extern crate std; use std::eprintln; -use super::{HInt, MinInt, i256, u256}; +use super::{DInt, HInt, MinInt, i256, u256}; use crate::support::{Int as _, NarrowingDiv}; const LOHI_SPLIT: u128 = 0xaaaaaaaaaaaaaaaaffffffffffffffff; @@ -98,6 +98,172 @@ fn not_u256() { assert_eq!(!u256::ZERO, u256::MAX); } +#[test] +fn shl_u256() { + let only_high = [ + 1, + u16::MAX.into(), + u32::MAX.into(), + u64::MAX.into(), + u128::MAX, + ]; + let mut has_errors = false; + + let mut add_error = |a, b, expected, actual| { + has_errors = true; + eprintln!( + "\ + FAILURE: {} << {b}\n\ + expected: {}\n\ + actual: {}\ + ", + hexu(a), + hexu(expected), + hexu(actual), + ); + }; + + for a in only_high { + for perturb in 0..10 { + let a = a.saturating_add(perturb); + for shift in 0..128 { + let res = u256::from_lo_hi(0, a) << shift; + let expected = u256::from_lo_hi(0, a << shift); + if res != expected { + add_error(a.widen(), shift, expected, res); + } + } + } + } + + let check = [ + ( + u256::MAX, + 1, + u256 { + lo: u128::MAX << 1, + hi: u128::MAX, + }, + ), + ( + u256::MAX, + 5, + u256 { + lo: u128::MAX << 5, + hi: u128::MAX, + }, + ), + ( + u256::MAX, + 63, + u256 { + lo: u128::MAX << 63, + hi: u128::MAX, + }, + ), + ( + u256::MAX, + 64, + u256 { + lo: (u64::MAX as u128) << 64, + hi: u128::MAX, + }, + ), + ( + u256::MAX, + 65, + u256 { + lo: (u64::MAX as u128) << 65, + hi: u128::MAX, + }, + ), + ( + u256::MAX, + 127, + u256 { + lo: 1 << 127, + hi: u128::MAX, + }, + ), + ( + u256::MAX, + 128, + u256 { + lo: 0, + hi: u128::MAX, + }, + ), + ( + u256::MAX, + 129, + u256 { + lo: 0, + hi: u128::MAX << 1, + }, + ), + ( + u256::MAX, + 191, + u256 { + lo: 0, + hi: u128::MAX << 63, + }, + ), + ( + u256::MAX, + 192, + u256 { + lo: 0, + hi: u128::MAX << 64, + }, + ), + ( + u256::MAX, + 193, + u256 { + lo: 0, + hi: u128::MAX << 65, + }, + ), + ( + u256::MAX, + 254, + u256 { + lo: 0, + hi: 0b11 << 126, + }, + ), + ( + u256::MAX, + 255, + u256 { + lo: 0, + hi: 1 << 127, + }, + ), + ( + u256 { + hi: 0, + lo: LOHI_SPLIT, + }, + 64, + u256 { + lo: 0xffffffffffffffff0000000000000000, + hi: 0xaaaaaaaaaaaaaaaa, + }, + ), + ]; + + for (input, shift, expected) in check { + let res = input << shift; + if res != expected { + add_error(input, shift, expected, res); + } + } + + assert!(!has_errors); +} + #[test] fn shr_u256() { let only_low = [ From a6de51188b8bb1322749d164a298b85e4f937252 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Sun, 22 Mar 2026 15:12:30 -0500 Subject: [PATCH 103/183] libm: Add tests against `rug` for `i256` --- .../compiler-builtins/libm-test/tests/u256.rs | 285 ++++++++++++++++-- .../libm/src/math/support/big.rs | 28 +- .../libm/src/math/support/big/tests.rs | 9 +- 3 files changed, 278 insertions(+), 44 deletions(-) diff --git a/library/compiler-builtins/libm-test/tests/u256.rs b/library/compiler-builtins/libm-test/tests/u256.rs index dc8e90acb2d29..ce51236a259b9 100644 --- a/library/compiler-builtins/libm-test/tests/u256.rs +++ b/library/compiler-builtins/libm-test/tests/u256.rs @@ -5,11 +5,11 @@ use std::sync::LazyLock; -use libm::support::{HInt, u256}; +use libm::support::{HInt, i256, u256}; type BigInt = rug::Integer; -use libm_test::bigint_fuzz_iteration_count; use libm_test::generate::random::SEED; +use libm_test::{MinInt, bigint_fuzz_iteration_count}; use rand::{RngExt, SeedableRng}; use rand_chacha::ChaCha8Rng; use rug::Assign; @@ -25,27 +25,56 @@ fn random_u256(rng: &mut ChaCha8Rng) -> u256 { u256 { lo, hi } } -fn assign_bigint(bx: &mut BigInt, x: u256) { - bx.assign_digits(&[x.lo, x.hi], Order::Lsf); +fn random_i256(rng: &mut ChaCha8Rng) -> i256 { + random_u256(rng).signed() } -fn from_bigint(bx: &mut BigInt) -> u256 { +fn assign_bigint_u256(bx: &mut BigInt, x: u256) { + bx.assign(x.hi); + *bx <<= 128; + *bx += x.lo; +} + +fn assign_bigint_i256(bx: &mut BigInt, x: i256) { + bx.assign(x.hi); + *bx <<= 128; + *bx += x.lo; +} + +/// Note that this destroys the result in `bx`. +fn from_bigint_u256(bx: &mut BigInt) -> u256 { // Truncate so the result fits into `[u128; 2]`. This makes all ops overflowing. *bx &= &*BIGINT_U256_MAX; let mut bres = [0u128, 0]; bx.write_digits(&mut bres, Order::Lsf); - bx.assign(0); + bx.assign(0); // prevent accidental reuse u256 { lo: bres[0], hi: bres[1], } } -fn check_one(msg: impl Fn() -> String, actual: u256, expected: &mut BigInt) { - let expected = from_bigint(expected); +/// Note that this destroys the result in `bx`. +fn from_bigint_i256(bx: &mut BigInt) -> i256 { + // Truncate so the result fits into `[u128; 2]`. This makes all ops overflowing. + *bx &= &*BIGINT_U256_MAX; + let lo = bx.to_u128_wrapping(); + *bx >>= 128; + let hi = bx.to_i128_wrapping(); + bx.assign(0); // prevent accidental reuse + i256 { hi, lo } +} + +#[track_caller] +fn assert_same_u256(msg: impl Fn() -> String, actual: u256, expected_big: &mut BigInt) { + let expected = from_bigint_u256(expected_big); if actual != expected { + let mut act_big = BigInt::new(); + assign_bigint_u256(&mut act_big, actual); panic!( "Test failure: {}\n\ + actual: {act_big}\n\ + expected: {expected_big}\n\ actual: {actual:#x}\n\ expected: {expected:#x}\ ", @@ -54,6 +83,98 @@ fn check_one(msg: impl Fn() -> String, actual: u256, expected: &mut BigInt) { } } +#[track_caller] +fn assert_same_i256(msg: impl Fn() -> String, actual: i256, expected_big: &mut BigInt) { + let expected = from_bigint_i256(expected_big); + if actual != expected { + let mut act_big = BigInt::new(); + assign_bigint_i256(&mut act_big, actual); + panic!( + "Test failure: {}\n\ + actual: {act_big}\n\ + expected: {expected_big}\n\ + actual: {actual:#x}\n\ + expected: {expected:#x}\ + ", + msg() + ) + } +} + +/// Verify the test setup. +#[test] +fn mp_u256_roundtrip() { + let mut rng = ChaCha8Rng::from_seed(*SEED); + let mut bx = BigInt::new(); + + for _ in 0..bigint_fuzz_iteration_count() { + let x = random_u256(&mut rng); + assign_bigint_u256(&mut bx, x); + assert_eq!(from_bigint_u256(&mut bx), x); + } + + // Check wraparound + assign_bigint_u256(&mut bx, u256::MAX); + bx += 1; + assert_eq!(from_bigint_u256(&mut bx), u256::MIN); + assign_bigint_u256(&mut bx, u256::MIN); + bx -= 1; + assert_eq!(from_bigint_u256(&mut bx), u256::MAX); +} + +/// Verify the test setup. +#[test] +fn mp_i256_roundtrip() { + let mut rng = ChaCha8Rng::from_seed(*SEED); + let mut bx = BigInt::new(); + + for _ in 0..bigint_fuzz_iteration_count() { + let x = random_i256(&mut rng); + assign_bigint_i256(&mut bx, x); + assert_eq!(from_bigint_i256(&mut bx), x); + } + + // Check wraparound + assign_bigint_i256(&mut bx, i256::MAX); + bx += 1; + assert_eq!(from_bigint_i256(&mut bx), i256::MIN); + assign_bigint_i256(&mut bx, i256::MIN); + bx -= 1; + assert_eq!(from_bigint_i256(&mut bx), i256::MAX); +} + +#[test] +fn mp_u256_ord() { + let mut rng = ChaCha8Rng::from_seed(*SEED); + let mut bx = BigInt::new(); + let mut by = BigInt::new(); + + for _ in 0..bigint_fuzz_iteration_count() { + let x = random_u256(&mut rng); + let y = random_u256(&mut rng); + assign_bigint_u256(&mut bx, x); + assign_bigint_u256(&mut by, y); + + assert_eq!(x.cmp(&y), bx.cmp(&by), "cmp({x:#x}, {y:#x})"); + } +} + +#[test] +fn mp_i256_ord() { + let mut rng = ChaCha8Rng::from_seed(*SEED); + let mut bx = BigInt::new(); + let mut by = BigInt::new(); + + for _ in 0..bigint_fuzz_iteration_count() { + let x = random_i256(&mut rng); + let y = random_i256(&mut rng); + assign_bigint_i256(&mut bx, x); + assign_bigint_i256(&mut by, y); + + assert_eq!(x.cmp(&y), bx.cmp(&by), "cmp({x:#x}, {y:#x})"); + } +} + #[test] fn mp_u256_bitor() { let mut rng = ChaCha8Rng::from_seed(*SEED); @@ -63,11 +184,28 @@ fn mp_u256_bitor() { for _ in 0..bigint_fuzz_iteration_count() { let x = random_u256(&mut rng); let y = random_u256(&mut rng); - assign_bigint(&mut bx, x); - assign_bigint(&mut by, y); + assign_bigint_u256(&mut bx, x); + assign_bigint_u256(&mut by, y); + let actual = x | y; + bx |= &by; + assert_same_u256(|| format!("{x:#x} ^ {y:#x}"), actual, &mut bx); + } +} + +#[test] +fn mp_i256_bitor() { + let mut rng = ChaCha8Rng::from_seed(*SEED); + let mut bx = BigInt::new(); + let mut by = BigInt::new(); + + for _ in 0..bigint_fuzz_iteration_count() { + let x = random_i256(&mut rng); + let y = random_i256(&mut rng); + assign_bigint_i256(&mut bx, x); + assign_bigint_i256(&mut by, y); let actual = x | y; bx |= &by; - check_one(|| format!("{x:#x} ^ {y:#x}"), actual, &mut bx); + assert_same_i256(|| format!("{x:#x} ^ {y:#x}"), actual, &mut bx); } } @@ -78,10 +216,24 @@ fn mp_u256_not() { for _ in 0..bigint_fuzz_iteration_count() { let x = random_u256(&mut rng); - assign_bigint(&mut bx, x); + assign_bigint_u256(&mut bx, x); let actual = !x; bx.not_assign(); - check_one(|| format!("!{x:#x}"), actual, &mut bx); + assert_same_u256(|| format!("!{x:#x}"), actual, &mut bx); + } +} + +#[test] +fn mp_i256_not() { + let mut rng = ChaCha8Rng::from_seed(*SEED); + let mut bx = BigInt::new(); + + for _ in 0..bigint_fuzz_iteration_count() { + let x = random_i256(&mut rng); + assign_bigint_i256(&mut bx, x); + let actual = !x; + bx.not_assign(); + assert_same_i256(|| format!("!{x:#x}"), actual, &mut bx); } } @@ -94,8 +246,9 @@ fn mp_u256_add() { for _ in 0..bigint_fuzz_iteration_count() { let x = random_u256(&mut rng); let y = random_u256(&mut rng); - assign_bigint(&mut bx, x); - assign_bigint(&mut by, y); + assign_bigint_u256(&mut bx, x); + assign_bigint_u256(&mut by, y); + // Emulate wrapping semantics with panicking ops let actual = if u256::MAX - x >= y { x + y } else { @@ -104,7 +257,35 @@ fn mp_u256_add() { y - (u256::MAX - x) - 1_u128.widen() }; bx += &by; - check_one(|| format!("{x:#x} + {y:#x}"), actual, &mut bx); + assert_same_u256(|| format!("{x:#x} + {y:#x}"), actual, &mut bx); + } +} + +#[test] +fn mp_i256_add() { + let mut rng = ChaCha8Rng::from_seed(*SEED); + let mut bx = BigInt::new(); + let mut by = BigInt::new(); + + for _ in 0..bigint_fuzz_iteration_count() { + let x = random_i256(&mut rng); + let y = random_i256(&mut rng); + assign_bigint_i256(&mut bx, x); + assign_bigint_i256(&mut by, y); + + // Emulate wrapping semantics with panicking ops + let actual = if x > i256::ZERO && y > i256::MAX - x { + // Overflow condition + (x + i256::MIN) + (y + i256::MIN) + } else if x < i256::ZERO && y < i256::MIN - x { + // Underflow condition + (x - i256::MIN) + (y - i256::MIN) + } else { + // Otherwise there is no overflow + x + y + }; + bx += &by; + assert_same_i256(|| format!("{x:#x} + {y:#x}"), actual, &mut bx); } } @@ -117,15 +298,41 @@ fn mp_u256_sub() { for _ in 0..bigint_fuzz_iteration_count() { let x = random_u256(&mut rng); let y = random_u256(&mut rng); - assign_bigint(&mut bx, x); - assign_bigint(&mut by, y); + assign_bigint_u256(&mut bx, x); + assign_bigint_u256(&mut by, y); // since the operators (may) panic on overflow, // we should test something that doesn't let actual = if x >= y { x - y } else { y - x }; bx -= &by; bx.abs_mut(); - check_one(|| format!("{x:#x} - {y:#x}"), actual, &mut bx); + assert_same_u256(|| format!("{x:#x} - {y:#x}"), actual, &mut bx); + } +} + +#[test] +fn mp_i256_sub() { + let mut rng = ChaCha8Rng::from_seed(*SEED); + let mut bx = BigInt::new(); + let mut by = BigInt::new(); + + for _ in 0..bigint_fuzz_iteration_count() { + let x = random_i256(&mut rng); + let y = random_i256(&mut rng); + assign_bigint_i256(&mut bx, x); + assign_bigint_i256(&mut by, y); + dbg!(&bx, &by); + + // Emulate wrapping semantics with panicking ops + let actual = if y > i256::ZERO && x < i256::MIN + y { + (x - i256::MIN) - (y + i256::MIN) + } else if y < i256::ZERO && x > i256::MAX + y { + (x + i256::MIN) - (y - i256::MIN) + } else { + x - y + }; + bx -= &by; + assert_same_i256(|| format!("{x:#x} - {y:#x}"), actual, &mut bx); } } @@ -137,10 +344,25 @@ fn mp_u256_shl() { for _ in 0..bigint_fuzz_iteration_count() { let x = random_u256(&mut rng); let shift: u32 = rng.random_range(0..256); - assign_bigint(&mut bx, x); + assign_bigint_u256(&mut bx, x); + let actual = x << shift; + bx <<= shift; + assert_same_u256(|| format!("{x:#x} << {shift}"), actual, &mut bx); + } +} + +#[test] +fn mp_i256_shl() { + let mut rng = ChaCha8Rng::from_seed(*SEED); + let mut bx = BigInt::new(); + + for _ in 0..bigint_fuzz_iteration_count() { + let x = random_i256(&mut rng); + let shift: u32 = rng.random_range(0..256); + assign_bigint_i256(&mut bx, x); let actual = x << shift; bx <<= shift; - check_one(|| format!("{x:#x} << {shift}"), actual, &mut bx); + assert_same_i256(|| format!("{x:#x} << {shift}"), actual, &mut bx); } } @@ -152,10 +374,25 @@ fn mp_u256_shr() { for _ in 0..bigint_fuzz_iteration_count() { let x = random_u256(&mut rng); let shift: u32 = rng.random_range(0..256); - assign_bigint(&mut bx, x); + assign_bigint_u256(&mut bx, x); + let actual = x >> shift; + bx >>= shift; + assert_same_u256(|| format!("{x:#x} >> {shift}"), actual, &mut bx); + } +} + +#[test] +fn mp_i256_shr() { + let mut rng = ChaCha8Rng::from_seed(*SEED); + let mut bx = BigInt::new(); + + for _ in 0..bigint_fuzz_iteration_count() { + let x = random_i256(&mut rng); + let shift: u32 = rng.random_range(0..256); + assign_bigint_i256(&mut bx, x); let actual = x >> shift; bx >>= shift; - check_one(|| format!("{x:#x} >> {shift}"), actual, &mut bx); + assert_same_i256(|| format!("{x:#x} >> {shift}"), actual, &mut bx); } } @@ -172,7 +409,7 @@ fn mp_u256_u128_widen_mul() { by.assign(y); let actual = x.widen_mul(y); bx *= &by; - check_one( + assert_same_u256( || format!("{x:#034x}.widen_mul({y:#034x})"), actual, &mut bx, diff --git a/library/compiler-builtins/libm/src/math/support/big.rs b/library/compiler-builtins/libm/src/math/support/big.rs index 24e3fbf11461c..c316d93f524ab 100644 --- a/library/compiler-builtins/libm/src/math/support/big.rs +++ b/library/compiler-builtins/libm/src/math/support/big.rs @@ -18,11 +18,11 @@ pub struct u256 { } impl u256 { - #[cfg(any(test, feature = "unstable-public-internals"))] pub const MAX: Self = Self { lo: u128::MAX, hi: u128::MAX, }; + pub const MIN: Self = Self { lo: 0, hi: 0 }; /// Reinterpret as a signed integer pub fn signed(self) -> i256 { @@ -42,6 +42,15 @@ pub struct i256 { } impl i256 { + pub const MAX: Self = Self { + lo: u128::MAX, + hi: i128::MAX, + }; + pub const MIN: Self = Self { + lo: u128::MIN, + hi: i128::MIN, + }; + /// Reinterpret as an unsigned integer pub fn unsigned(self) -> u256 { u256 { @@ -60,11 +69,8 @@ impl MinInt for u256 { const BITS: u32 = 256; const ZERO: Self = Self { lo: 0, hi: 0 }; const ONE: Self = Self { lo: 1, hi: 0 }; - const MIN: Self = Self { lo: 0, hi: 0 }; - const MAX: Self = Self { - lo: u128::MAX, - hi: u128::MAX, - }; + const MIN: Self = Self::MIN; + const MAX: Self = Self::MAX; } impl MinInt for i256 { @@ -76,14 +82,8 @@ impl MinInt for i256 { const BITS: u32 = 256; const ZERO: Self = Self { lo: 0, hi: 0 }; const ONE: Self = Self { lo: 1, hi: 0 }; - const MIN: Self = Self { - lo: u128::MIN, - hi: i128::MIN, - }; - const MAX: Self = Self { - lo: u128::MAX, - hi: i128::MAX, - }; + const MIN: Self = Self::MIN; + const MAX: Self = Self::MAX; } macro_rules! impl_common { diff --git a/library/compiler-builtins/libm/src/math/support/big/tests.rs b/library/compiler-builtins/libm/src/math/support/big/tests.rs index 4397b4478bb8d..0ac8f9721a4dd 100644 --- a/library/compiler-builtins/libm/src/math/support/big/tests.rs +++ b/library/compiler-builtins/libm/src/math/support/big/tests.rs @@ -113,13 +113,10 @@ fn shl_u256() { has_errors = true; eprintln!( "\ - FAILURE: {} << {b}\n\ - expected: {}\n\ - actual: {}\ + FAILURE: {a:#x} << {b}\n\ + expected: {expected:#x}\n\ + actual: {actual:#x}\ ", - hexu(a), - hexu(expected), - hexu(actual), ); }; From a4fe265df0b68bb1264d562b10276d18af1172e7 Mon Sep 17 00:00:00 2001 From: Brian Cain Date: Tue, 7 Apr 2026 16:15:04 -0700 Subject: [PATCH 104/183] hexagon: Implement `__clear_cache` using inline assembly Implement `__clear_cache` for Hexagon targets in Rust. Hexagon has separate instruction and data caches, so this flushes dirty data cache lines with `dccleaninva`, invalidates stale instruction cache lines with `icinva`, then issues an `isync` barrier. Based on the compiler-rt implementation from llvm/llvm-project#188411. --- .../compiler-builtins/src/hexagon.rs | 44 +++++++++++++++++++ 1 file changed, 44 insertions(+) diff --git a/library/compiler-builtins/compiler-builtins/src/hexagon.rs b/library/compiler-builtins/compiler-builtins/src/hexagon.rs index 170c786bbf517..46062fc3700d8 100644 --- a/library/compiler-builtins/compiler-builtins/src/hexagon.rs +++ b/library/compiler-builtins/compiler-builtins/src/hexagon.rs @@ -1,5 +1,49 @@ use core::arch::global_asm; +// Hexagon L1 cache line size in bytes (Hexagon PRM sections 5.10.3-5.10.4). +const CACHE_LINE_SIZE: usize = 32; + +intrinsics! { + pub unsafe extern "C" fn __clear_cache(start: *mut u8, end: *mut u8) { + // Hexagon has separate instruction and data caches. + let mask = !(CACHE_LINE_SIZE - 1); + let start_line = start.addr() & mask; + let end_addr = end.addr(); + + // Clean and invalidate data cache to push new code to memory and + // invalidate stale lines in the L2 cache. + let mut addr = start_line; + while addr < end_addr { + unsafe { + core::arch::asm!( + "dccleaninva({addr})", + addr = in(reg) addr, + options(nostack, preserves_flags), + ); + } + addr += CACHE_LINE_SIZE; + } + + // Invalidate instruction cache so it re-fetches from memory. + addr = start_line; + while addr < end_addr { + unsafe { + core::arch::asm!( + "icinva({addr})", + addr = in(reg) addr, + options(nostack, preserves_flags), + ); + } + addr += CACHE_LINE_SIZE; + } + + // Instruction sync barrier ensures subsequent fetches see the new code. + unsafe { + core::arch::asm!("isync", options(nostack, preserves_flags)); + } + } +} + global_asm!(include_str!("hexagon/func_macro.s"), options(raw)); global_asm!( From c2c30c90379420591c1c21b5ce3e7f7ef948eb6b Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Wed, 8 Apr 2026 03:57:07 -0400 Subject: [PATCH 105/183] hex: Eliminate parser hacks needed for the previous MSRV --- .../libm/src/math/support/hex_float.rs | 195 +++++++++--------- 1 file changed, 95 insertions(+), 100 deletions(-) diff --git a/library/compiler-builtins/libm/src/math/support/hex_float.rs b/library/compiler-builtins/libm/src/math/support/hex_float.rs index 28aab7ef27a1c..ecbbf377dc5d2 100644 --- a/library/compiler-builtins/libm/src/math/support/hex_float.rs +++ b/library/compiler-builtins/libm/src/math/support/hex_float.rs @@ -879,62 +879,59 @@ mod tests_panicking { extern crate std; use super::*; - // HACK(msrv): 1.63 rejects unknown width float literals at an AST level, so use a macro to - // hide them from the AST. + #[test] #[cfg(f16_enabled)] - macro_rules! f16_tests { - () => { - #[test] - fn test_f16_almost_extra_precision() { - // Exact maximum precision allowed - hf16("0x1.ffcp+0"); - } - - #[test] - #[should_panic(expected = "the value is too precise")] - fn test_f16_extra_precision() { - // One bit more than the above. - hf16("0x1.ffdp+0"); - } + fn test_f16_almost_extra_precision() { + // Exact maximum precision allowed + hf16("0x1.ffcp+0"); + } - #[test] - #[should_panic(expected = "the value is too huge")] - fn test_f16_overflow() { - // One bit more than the above. - hf16("0x1p+16"); - } + #[test] + #[cfg(f16_enabled)] + #[should_panic(expected = "the value is too precise")] + fn test_f16_extra_precision() { + // One bit more than the above. + hf16("0x1.ffdp+0"); + } - #[test] - fn test_f16_tiniest() { - let x = hf16("0x1.p-24"); - let y = hf16("0x0.001p-12"); - let z = hf16("0x0.8p-23"); - assert_eq!(x, y); - assert_eq!(x, z); - } + #[test] + #[cfg(f16_enabled)] + #[should_panic(expected = "the value is too huge")] + fn test_f16_overflow() { + // One bit more than the above. + hf16("0x1p+16"); + } - #[test] - #[should_panic(expected = "the value is too tiny")] - fn test_f16_too_tiny() { - hf16("0x1.p-25"); - } + #[test] + #[cfg(f16_enabled)] + fn test_f16_tiniest() { + let x = hf16("0x1.p-24"); + let y = hf16("0x0.001p-12"); + let z = hf16("0x0.8p-23"); + assert_eq!(x, y); + assert_eq!(x, z); + } - #[test] - #[should_panic(expected = "the value is too tiny")] - fn test_f16_also_too_tiny() { - hf16("0x0.8p-24"); - } + #[test] + #[cfg(f16_enabled)] + #[should_panic(expected = "the value is too tiny")] + fn test_f16_too_tiny() { + hf16("0x1.p-25"); + } - #[test] - #[should_panic(expected = "the value is too tiny")] - fn test_f16_again_too_tiny() { - hf16("0x0.001p-13"); - } - }; + #[test] + #[cfg(f16_enabled)] + #[should_panic(expected = "the value is too tiny")] + fn test_f16_also_too_tiny() { + hf16("0x0.8p-24"); } + #[test] #[cfg(f16_enabled)] - f16_tests!(); + #[should_panic(expected = "the value is too tiny")] + fn test_f16_again_too_tiny() { + hf16("0x0.001p-13"); + } #[test] fn test_f32_almost_extra_precision() { @@ -1003,68 +1000,66 @@ mod tests_panicking { hf64("0x1.abcdabcdabcdf8p+0"); } - // HACK(msrv): 1.63 rejects unknown width float literals at an AST level, so use a macro to - // hide them from the AST. + #[test] #[cfg(f128_enabled)] - macro_rules! f128_tests { - () => { - #[test] - fn test_f128_almost_extra_precision() { - // Exact maximum precision allowed - hf128("0x1.ffffffffffffffffffffffffffffp+16383"); - } - - #[test] - #[should_panic(expected = "the value is too precise")] - fn test_f128_extra_precision() { - // Just below the maximum finite. - hf128("0x1.fffffffffffffffffffffffffffe8p+16383"); - } - #[test] - #[should_panic(expected = "the value is too huge")] - fn test_f128_extra_precision_overflow() { - // One bit more than the above. Should overflow. - hf128("0x1.ffffffffffffffffffffffffffff8p+16383"); - } + fn test_f128_almost_extra_precision() { + // Exact maximum precision allowed + hf128("0x1.ffffffffffffffffffffffffffffp+16383"); + } - #[test] - #[should_panic(expected = "the value is too huge")] - fn test_f128_overflow() { - // One bit more than the above. - hf128("0x1p+16384"); - } + #[test] + #[cfg(f128_enabled)] + #[should_panic(expected = "the value is too precise")] + fn test_f128_extra_precision() { + // Just below the maximum finite. + hf128("0x1.fffffffffffffffffffffffffffe8p+16383"); + } + #[test] + #[cfg(f128_enabled)] + #[should_panic(expected = "the value is too huge")] + fn test_f128_extra_precision_overflow() { + // One bit more than the above. Should overflow. + hf128("0x1.ffffffffffffffffffffffffffff8p+16383"); + } - #[test] - fn test_f128_tiniest() { - let x = hf128("0x1.p-16494"); - let y = hf128("0x0.0000000000000001p-16430"); - let z = hf128("0x0.8p-16493"); - assert_eq!(x, y); - assert_eq!(x, z); - } + #[test] + #[cfg(f128_enabled)] + #[should_panic(expected = "the value is too huge")] + fn test_f128_overflow() { + // One bit more than the above. + hf128("0x1p+16384"); + } - #[test] - #[should_panic(expected = "the value is too tiny")] - fn test_f128_too_tiny() { - hf128("0x1.p-16495"); - } + #[test] + #[cfg(f128_enabled)] + fn test_f128_tiniest() { + let x = hf128("0x1.p-16494"); + let y = hf128("0x0.0000000000000001p-16430"); + let z = hf128("0x0.8p-16493"); + assert_eq!(x, y); + assert_eq!(x, z); + } - #[test] - #[should_panic(expected = "the value is too tiny")] - fn test_f128_again_too_tiny() { - hf128("0x0.0000000000000001p-16431"); - } + #[test] + #[cfg(f128_enabled)] + #[should_panic(expected = "the value is too tiny")] + fn test_f128_too_tiny() { + hf128("0x1.p-16495"); + } - #[test] - #[should_panic(expected = "the value is too tiny")] - fn test_f128_also_too_tiny() { - hf128("0x0.8p-16494"); - } - }; + #[test] + #[cfg(f128_enabled)] + #[should_panic(expected = "the value is too tiny")] + fn test_f128_again_too_tiny() { + hf128("0x0.0000000000000001p-16431"); } + #[test] #[cfg(f128_enabled)] - f128_tests!(); + #[should_panic(expected = "the value is too tiny")] + fn test_f128_also_too_tiny() { + hf128("0x0.8p-16494"); + } } #[cfg(test)] From 5c66a580832b31f8926d1a66b20fa094027f9b49 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Wed, 8 Apr 2026 03:55:10 -0400 Subject: [PATCH 106/183] hex: Always print a leading `+` sign and the NaN payload This is for debugging so always give us all useful output. --- .../libm/src/math/support/hex_float.rs | 117 ++++++++++++------ .../libm/src/math/support/mod.rs | 7 ++ 2 files changed, 87 insertions(+), 37 deletions(-) diff --git a/library/compiler-builtins/libm/src/math/support/hex_float.rs b/library/compiler-builtins/libm/src/math/support/hex_float.rs index ecbbf377dc5d2..933b2f640afef 100644 --- a/library/compiler-builtins/libm/src/math/support/hex_float.rs +++ b/library/compiler-builtins/libm/src/math/support/hex_float.rs @@ -329,19 +329,29 @@ const fn hex_digit(c: u8) -> Option { mod hex_fmt { use core::fmt; - use crate::support::Float; + use crate::support::{Float, div_ceil_u32}; // Adapted from https://github.com/ericseppanen/hexfloat2/blob/a5c27932f0ff/src/format.rs pub(super) fn fmt_any_hex(x: &F, f: &mut fmt::Formatter<'_>) -> fmt::Result { if x.is_sign_negative() { write!(f, "-")?; + } else { + write!(f, "+")?; + } + + if x.is_nan() { + if x.is_snan() { + write!(f, "sNaN")?; + } else if x.is_nan() { + write!(f, "qNaN")?; + } + let payload = x.frac() & !F::SIG_TOP_BIT; + let width = div_ceil_u32(F::SIG_BITS, 4) as usize + 2; + write!(f, "({payload:#0width$x})")?; + return Ok(()); } - if x.is_snan() { - return write!(f, "sNaN"); - } else if x.is_nan() { - return write!(f, "qNaN"); - } else if x.is_infinite() { + if x.is_infinite() { return write!(f, "inf"); } else if *x == F::ZERO { return write!(f, "0x0p+0"); @@ -478,7 +488,8 @@ mod hex_fmt { #[cfg(test)] mod parse_tests { extern crate std; - use std::string::String; + + use std::string::{String, ToString}; use std::{format, println}; use super::*; @@ -528,13 +539,17 @@ mod parse_tests { Ok(()) } + /// Strip the qNaN/sNaN and payload since we don't parse that. #[cfg_attr(not(f16_enabled), expect(unused))] - pub fn canonicalize_snan_str(s: String) -> String { + pub fn canonicalize_snan_str(mut s: String) -> String { if s.contains("sNaN") || s.contains("qNaN") { - s.replace("sNaN", "NaN").replace("qNaN", "NaN") - } else { - s + s = s.replace("sNaN", "NaN").replace("qNaN", "NaN"); + if let Some((nan, payload)) = s.split_once("(") { + assert!(payload.ends_with(")")); + s = nan.to_string(); + } } + s } #[test] @@ -1141,46 +1156,55 @@ mod print_tests { } #[test] fn spot_checks() { - assert_eq!(Hex(f32::MAX).to_string(), "0x1.fffffep+127"); - assert_eq!(Hex(f64::MAX).to_string(), "0x1.fffffffffffffp+1023"); + assert_eq!(Hex(f32::MAX).to_string(), "+0x1.fffffep+127"); + assert_eq!(Hex(f64::MAX).to_string(), "+0x1.fffffffffffffp+1023"); assert_eq!(Hex(f32::MIN).to_string(), "-0x1.fffffep+127"); assert_eq!(Hex(f64::MIN).to_string(), "-0x1.fffffffffffffp+1023"); - assert_eq!(Hex(f32::ZERO).to_string(), "0x0p+0"); - assert_eq!(Hex(f64::ZERO).to_string(), "0x0p+0"); + assert_eq!(Hex(f32::ZERO).to_string(), "+0x0p+0"); + assert_eq!(Hex(f64::ZERO).to_string(), "+0x0p+0"); assert_eq!(Hex(f32::NEG_ZERO).to_string(), "-0x0p+0"); assert_eq!(Hex(f64::NEG_ZERO).to_string(), "-0x0p+0"); - assert_eq!(Hex(f32::NAN).to_string(), "qNaN"); - assert_eq!(Hex(f64::NAN).to_string(), "qNaN"); - assert_eq!(Hex(f32::NEG_NAN).to_string(), "-qNaN"); - assert_eq!(Hex(f64::NEG_NAN).to_string(), "-qNaN"); + assert_eq!(Hex(f32::NAN).to_string(), "+qNaN(0x000000)"); + assert_eq!(Hex(f64::NAN).to_string(), "+qNaN(0x0000000000000)"); + assert_eq!(Hex(f32::NEG_NAN).to_string(), "-qNaN(0x000000)"); + assert_eq!(Hex(f64::NEG_NAN).to_string(), "-qNaN(0x0000000000000)"); if !cfg!(x86_no_sse2) { // FIXME(rust-lang/rust#115567): calls quiet the sNaN - assert_eq!(Hex(f32::SNAN).to_string(), "sNaN"); - assert_eq!(Hex(f64::SNAN).to_string(), "sNaN"); - assert_eq!(Hex(f32::NEG_SNAN).to_string(), "-sNaN"); - assert_eq!(Hex(f64::NEG_SNAN).to_string(), "-sNaN"); + assert_eq!(Hex(f32::SNAN).to_string(), "+sNaN(0x200000)"); + assert_eq!(Hex(f64::SNAN).to_string(), "+sNaN(0x4000000000000)"); + assert_eq!(Hex(f32::NEG_SNAN).to_string(), "-sNaN(0x200000)"); + assert_eq!(Hex(f64::NEG_SNAN).to_string(), "-sNaN(0x4000000000000)"); + assert_eq!(Hex(f32::from_bits(u32::MAX)).to_string(), "-qNaN(0x3fffff)"); + assert_eq!( + Hex(f64::from_bits(u64::MAX)).to_string(), + "-qNaN(0x7ffffffffffff)" + ); } - assert_eq!(Hex(f32::INFINITY).to_string(), "inf"); - assert_eq!(Hex(f64::INFINITY).to_string(), "inf"); + assert_eq!(Hex(f32::INFINITY).to_string(), "+inf"); + assert_eq!(Hex(f64::INFINITY).to_string(), "+inf"); assert_eq!(Hex(f32::NEG_INFINITY).to_string(), "-inf"); assert_eq!(Hex(f64::NEG_INFINITY).to_string(), "-inf"); #[cfg(f16_enabled)] { - assert_eq!(Hex(f16::MAX).to_string(), "0x1.ffcp+15"); + assert_eq!(Hex(f16::MAX).to_string(), "+0x1.ffcp+15"); assert_eq!(Hex(f16::MIN).to_string(), "-0x1.ffcp+15"); - assert_eq!(Hex(f16::ZERO).to_string(), "0x0p+0"); + assert_eq!(Hex(f16::ZERO).to_string(), "+0x0p+0"); assert_eq!(Hex(f16::NEG_ZERO).to_string(), "-0x0p+0"); - assert_eq!(Hex(f16::NAN).to_string(), "qNaN"); - assert_eq!(Hex(f16::SNAN).to_string(), "sNaN"); - assert_eq!(Hex(f16::NEG_NAN).to_string(), "-qNaN"); - assert_eq!(Hex(f16::INFINITY).to_string(), "inf"); + + assert_eq!(Hex(f16::NAN).to_string(), "+qNaN(0x000)"); + assert_eq!(Hex(f16::SNAN).to_string(), "+sNaN(0x100)"); + assert_eq!(Hex(f16::NEG_NAN).to_string(), "-qNaN(0x000)"); + assert_eq!(Hex(f16::NEG_SNAN).to_string(), "-sNaN(0x100)"); + assert_eq!(Hex(f16::from_bits(u16::MAX)).to_string(), "-qNaN(0x1ff)"); + + assert_eq!(Hex(f16::INFINITY).to_string(), "+inf"); assert_eq!(Hex(f16::NEG_INFINITY).to_string(), "-inf"); } @@ -1188,18 +1212,37 @@ mod print_tests { { assert_eq!( Hex(f128::MAX).to_string(), - "0x1.ffffffffffffffffffffffffffffp+16383" + "+0x1.ffffffffffffffffffffffffffffp+16383" ); assert_eq!( Hex(f128::MIN).to_string(), "-0x1.ffffffffffffffffffffffffffffp+16383" ); - assert_eq!(Hex(f128::ZERO).to_string(), "0x0p+0"); + assert_eq!(Hex(f128::ZERO).to_string(), "+0x0p+0"); assert_eq!(Hex(f128::NEG_ZERO).to_string(), "-0x0p+0"); - assert_eq!(Hex(f128::NAN).to_string(), "qNaN"); - assert_eq!(Hex(f128::SNAN).to_string(), "sNaN"); - assert_eq!(Hex(f128::NEG_NAN).to_string(), "-qNaN"); - assert_eq!(Hex(f128::INFINITY).to_string(), "inf"); + + assert_eq!( + Hex(f128::NAN).to_string(), + "+qNaN(0x0000000000000000000000000000)" + ); + assert_eq!( + Hex(f128::SNAN).to_string(), + "+sNaN(0x4000000000000000000000000000)" + ); + assert_eq!( + Hex(f128::NEG_NAN).to_string(), + "-qNaN(0x0000000000000000000000000000)" + ); + assert_eq!( + Hex(f128::NEG_SNAN).to_string(), + "-sNaN(0x4000000000000000000000000000)" + ); + assert_eq!( + Hex(f128::from_bits(u128::MAX)).to_string(), + "-qNaN(0x7fffffffffffffffffffffffffff)" + ); + + assert_eq!(Hex(f128::INFINITY).to_string(), "+inf"); assert_eq!(Hex(f128::NEG_INFINITY).to_string(), "-inf"); } } diff --git a/library/compiler-builtins/libm/src/math/support/mod.rs b/library/compiler-builtins/libm/src/math/support/mod.rs index f28c021040da7..8bca2e60c7df8 100644 --- a/library/compiler-builtins/libm/src/math/support/mod.rs +++ b/library/compiler-builtins/libm/src/math/support/mod.rs @@ -68,3 +68,10 @@ pub unsafe fn unchecked_div_isize(x: isize, y: isize) -> isize { } } } + +// FIXME(msrv): `div_ceil` is stablein 1.73. +pub fn div_ceil_u32(a: u32, b: u32) -> u32 { + let d = a / b; + let r = a % b; + if r > 0 { d + 1 } else { d } +} From dd79b039e46ca71fd3989b528d091ab2b46edf7f Mon Sep 17 00:00:00 2001 From: Lewis McClelland Date: Thu, 9 Apr 2026 22:20:11 -0400 Subject: [PATCH 107/183] Add docs about SDKs on armv7a-vex-v5 --- .../src/platform-support/armv7a-vex-v5.md | 26 ++++++++++++++++--- 1 file changed, 23 insertions(+), 3 deletions(-) diff --git a/src/doc/rustc/src/platform-support/armv7a-vex-v5.md b/src/doc/rustc/src/platform-support/armv7a-vex-v5.md index 611ec04b42c8a..b5d7e82f9689c 100644 --- a/src/doc/rustc/src/platform-support/armv7a-vex-v5.md +++ b/src/doc/rustc/src/platform-support/armv7a-vex-v5.md @@ -22,20 +22,30 @@ This target is cross-compiled. Dynamic linking is unsupported. `#![no_std]` crates can be built using `build-std` to build `core` and `panic_abort` and optionally `alloc`. Unwinding panics are not yet supported on this target. `std` has only partial support due to platform limitations. Notably: + - `std::process` and `std::net` are unimplemented. `std::thread` only supports sleeping and yielding, as this is a single-threaded environment. - `std::time` has full support for `Instant`, but no support for `SystemTime`. - `std::io` has full support for `stdin`/`stdout`/`stderr`. `stdout` and `stderr` both write to USB channel 1 on this platform and are not differentiated. -- `std::fs` has limited support for reading or writing to files. Directory operations, file deletion, and some file opening features are unsupported and will return errors. +- `std::fs` has limited support for reading or writing to files. The following features are unsupported: + - All directory operations (including mkdir and readdir), although reading directories is possible through [3rd party crates](https://docs.rs/vex-sdk/latest/vex_sdk/file/fn.vexFileDirectoryGet.html) + - Deleting files and directories + - File metadata other than file size and type (that is, file vs directory) + - Opening files with an uncommon combination of open options, such as read + write at the same time. + The supported modes for opening files are in read-only mode, append mode, or write mode (with or without truncation). - A global allocator implemented on top of `dlmalloc` is provided. - Modules that do not need to interact with the OS beyond allocation such as `std::collections`, `std::hash`, `std::future`, `std::sync`, etc are fully supported. - Random number generation and hashing is insecure, as there is no reliable source of entropy on this platform. -In order to support some APIs, users are expected to provide a supporting runtime SDK for `libstd` to link against. This library may be provided either by [`vex-sdk-build`](https://github.com/vexide/vex-sdk/tree/main/packages/vex-sdk-build) (which will download an official SDK from VEX) or through an open-source implementation such as [`vex-sdk-jumptable`](https://crates.io/crates/vex-sdk-jumptable). - When compiling for this target, the "C" calling convention maps to AAPCS with VFP registers (hard float ABI) and the "system" calling convention maps to AAPCS without VFP registers (softfp ABI). This target generates binaries in the ELF format that may be uploaded to the brain with external tools. +### Platform SDKs + +In order to use most platform-specific APIs, users must configure a supporting runtime SDK for `libstd` to link against. Official *VEXcode* SDKs from VEX can be downloaded and linked via the [`vex-sdk-vexcode`](https://crates.io/crates/vex-sdk-vexcode) crate, but they have a restrictive redistribution policy that might not be suitable for all projects. The suggested SDK for open-source projects is the community-supported [`vex-sdk-jumptable`](https://crates.io/crates/vex-sdk-jumptable) crate. SDK implementations are generally thin wrappers over system calls so projects should not expect to see significant differences in behavior depending on which SDK they use. + +Libraries may access symbols from the active VEX SDK without depending on a specific implementation by using the [`vex-sdk`](https://crates.io/crates/vex-sdk) crate. + ## Building the target You can build Rust with support for this target by adding it to the `target` list in `bootstrap.toml`, and then running `./x build --target armv7a-vex-v5 compiler`. @@ -78,6 +88,16 @@ Programs can also be directly uploaded to the brain over a USB connection immedi cargo v5 upload --release ``` +### Hello World program + +```rs +use ::vex_sdk_jumptable as _; // Bring VEX SDK symbols into scope + +fn main() { + println!("Hello, world"); +} +``` + ## Testing Binaries built for this target can be run in an emulator (such as [vex-v5-qemu](https://github.com/vexide/vex-v5-qemu)), or uploaded to a physical device over a serial (USB) connection. From c25fbebe15a9091ab6999c4de783b8c74ee0a4f3 Mon Sep 17 00:00:00 2001 From: Lewis McClelland Date: Thu, 9 Apr 2026 22:45:20 -0400 Subject: [PATCH 108/183] Add C compilation instructions --- .../src/platform-support/armv7a-vex-v5.md | 67 ++++++++++++++++++- 1 file changed, 66 insertions(+), 1 deletion(-) diff --git a/src/doc/rustc/src/platform-support/armv7a-vex-v5.md b/src/doc/rustc/src/platform-support/armv7a-vex-v5.md index b5d7e82f9689c..238947c1ff906 100644 --- a/src/doc/rustc/src/platform-support/armv7a-vex-v5.md +++ b/src/doc/rustc/src/platform-support/armv7a-vex-v5.md @@ -110,4 +110,69 @@ The Rust test suite for `library/std` is not yet supported. This target can be cross-compiled from any host. -Linking to C libraries is not supported. +The recommended configuration for compiling compatible C code is via the [Arm Toolchain for Embedded](https://github.com/arm/arm-toolchain/tree/arm-software/arm-software/embedded#readme) the following compilation flags: + +```sh +clang --target=arm-none-eabi -mcpu=cortex-a9 -mfpu=neon -mfloat-abi=hard -fno-pic -fno-exceptions -fno-rtti -funwind-tables +``` + +The following Cargo configuration can be used to link with picolibc (the libc used by the Arm Toolchain for Embedded): + +```toml +[target.armv7a-vex-v5] +# We use ARM Clang as a linker because ld.lld by itself doesn't include the +# multilib logic for resolving static libraries. +linker = "clang" + +rustflags = [ + # These link flags resolve to this sysroot: + # `…/arm-none-eabi/armv7a_hard_vfpv3_d16_unaligned` + # (hard float / VFP version 3 with 16 regs / unaligned access) + "-Clink-arg=--target=armv7a-none-eabihf", + + # To disable crt0 and use Rust's _boot implementation + # (or something custom): + #"-Clink-arg=-nostartfiles", + + # Explicit `-lc` required because Rust calls the linker with + # `-nodefaultlibs` which disables libc, libm, etc. + "-Clink-arg=-lc", +] +``` + +You may also want to set these environment variables so that 3rd party crates use the correct C compiler: + +```sh +PATH=/path/to/arm-toolchain/bin:$PATH +CC_armv7a_vex_v5=clang +AR_armv7a_vex_v5=clang +CFLAGS_armv7a_vex_v5=[See above] +``` + +### CMake + +It may be helpful to create a CMake toolchain like the following if you are depending on the `cmake` crate: + +```cmake +# toolchain.cmake +set(CMAKE_SYSTEM_NAME Generic) +set(CMAKE_SYSTEM_PROCESSOR arm) + +set(triple armv7a-none-eabihf) + +set(CMAKE_C_COMPILER clang) +set(CMAKE_C_COMPILER_TARGET ${triple}) +set(CMAKE_CXX_COMPILER clang++) +set(CMAKE_CXX_COMPILER_TARGET ${triple}) +set(CMAKE_TRY_COMPILE_TARGET_TYPE "STATIC_LIBRARY") +``` + +You can enable it by setting the following environment variable alongside the previously-mentioned environment variables: + +```sh +CMAKE_TOOLCHAIN_FILE_armv7a_vex_v5=/path/to/toolchain.cmake +``` + +### Implementation of libc functions + +You may have to implement [certain system support functions](https://github.com/picolibc/picolibc/blob/main/doc/os.md) for some parts of libc to work properly. From ae6376ad8fbff2959945509869e36efc442d0138 Mon Sep 17 00:00:00 2001 From: Lewis McClelland Date: Thu, 9 Apr 2026 22:55:58 -0400 Subject: [PATCH 109/183] Instruct users to build `std` (not `core`) on armv7a-vex-v5 --- src/doc/rustc/src/platform-support/armv7a-vex-v5.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/doc/rustc/src/platform-support/armv7a-vex-v5.md b/src/doc/rustc/src/platform-support/armv7a-vex-v5.md index 238947c1ff906..facd7ab9f5a8b 100644 --- a/src/doc/rustc/src/platform-support/armv7a-vex-v5.md +++ b/src/doc/rustc/src/platform-support/armv7a-vex-v5.md @@ -52,7 +52,7 @@ You can build Rust with support for this target by adding it to the `target` lis ## Building Rust programs -Rust does not yet ship pre-compiled artifacts for this target. To compile for this target, you will either need to build Rust with the target enabled (see "Building the target" above), or build your own copy of `core` by using `build-std` or similar. +Rust does not yet ship pre-compiled artifacts for this target. To compile for this target, you will either need to build Rust with the target enabled (see "Building the target" above), or build your own copy of `std` using `build-std` or similar. When the compiler builds a binary, an ELF build artifact will be produced. Additional tools are required for this artifact to be recognizable to VEXos as a user program. From df9fb65d624b9730f78a23d528844325348d59a0 Mon Sep 17 00:00:00 2001 From: Lewis McClelland Date: Thu, 9 Apr 2026 23:05:53 -0400 Subject: [PATCH 110/183] Fix grammar issues in armv7a-vex-v5 docs --- .../src/platform-support/armv7a-vex-v5.md | 20 +++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/src/doc/rustc/src/platform-support/armv7a-vex-v5.md b/src/doc/rustc/src/platform-support/armv7a-vex-v5.md index facd7ab9f5a8b..6b95888b897e0 100644 --- a/src/doc/rustc/src/platform-support/armv7a-vex-v5.md +++ b/src/doc/rustc/src/platform-support/armv7a-vex-v5.md @@ -4,7 +4,7 @@ Allows compiling user programs for the [VEX V5 Brain](https://www.vexrobotics.com/276-4810.html), a microcontroller for educational and competitive robotics. -Rust support for this target is not affiliated with VEX Robotics or IFI, and does not link to any official VEX SDK. +Rust support for this target is not affiliated with VEX Robotics or IFI, and does not link against any official VEX SDK. ## Target maintainers @@ -27,13 +27,13 @@ This target is cross-compiled. Dynamic linking is unsupported. - `std::time` has full support for `Instant`, but no support for `SystemTime`. - `std::io` has full support for `stdin`/`stdout`/`stderr`. `stdout` and `stderr` both write to USB channel 1 on this platform and are not differentiated. - `std::fs` has limited support for reading or writing to files. The following features are unsupported: - - All directory operations (including mkdir and readdir), although reading directories is possible through [3rd party crates](https://docs.rs/vex-sdk/latest/vex_sdk/file/fn.vexFileDirectoryGet.html) + - All directory operations (including `mkdir` and `readdir`), although reading directories is possible through [third-party crates](https://docs.rs/vex-sdk/latest/vex_sdk/file/fn.vexFileDirectoryGet.html) - Deleting files and directories - - File metadata other than file size and type (that is, file vs directory) + - File metadata other than file size and type (that is, file vs. directory) - Opening files with an uncommon combination of open options, such as read + write at the same time. The supported modes for opening files are in read-only mode, append mode, or write mode (with or without truncation). - A global allocator implemented on top of `dlmalloc` is provided. -- Modules that do not need to interact with the OS beyond allocation such as `std::collections`, `std::hash`, `std::future`, `std::sync`, etc are fully supported. +- Modules that do not need to interact with the OS beyond allocation, such as `std::collections`, `std::hash`, `std::future`, `std::sync`, etc., are fully supported. - Random number generation and hashing is insecure, as there is no reliable source of entropy on this platform. When compiling for this target, the "C" calling convention maps to AAPCS with VFP registers (hard float ABI) and the "system" calling convention maps to AAPCS without VFP registers (softfp ABI). @@ -42,7 +42,7 @@ This target generates binaries in the ELF format that may be uploaded to the bra ### Platform SDKs -In order to use most platform-specific APIs, users must configure a supporting runtime SDK for `libstd` to link against. Official *VEXcode* SDKs from VEX can be downloaded and linked via the [`vex-sdk-vexcode`](https://crates.io/crates/vex-sdk-vexcode) crate, but they have a restrictive redistribution policy that might not be suitable for all projects. The suggested SDK for open-source projects is the community-supported [`vex-sdk-jumptable`](https://crates.io/crates/vex-sdk-jumptable) crate. SDK implementations are generally thin wrappers over system calls so projects should not expect to see significant differences in behavior depending on which SDK they use. +To use most platform-specific APIs, users must configure a supporting runtime SDK for `libstd` to link against. Official *VEXcode* SDKs from VEX can be downloaded and linked via the [`vex-sdk-vexcode`](https://crates.io/crates/vex-sdk-vexcode) crate, but they have a restrictive redistribution policy that might not be suitable for all projects. The suggested SDK for open-source projects is the community-supported [`vex-sdk-jumptable`](https://crates.io/crates/vex-sdk-jumptable) crate. SDK implementations are generally thin wrappers over system calls, so projects should not expect to see significant differences in behavior depending on which SDK they use. Libraries may access symbols from the active VEX SDK without depending on a specific implementation by using the [`vex-sdk`](https://crates.io/crates/vex-sdk) crate. @@ -100,7 +100,7 @@ fn main() { ## Testing -Binaries built for this target can be run in an emulator (such as [vex-v5-qemu](https://github.com/vexide/vex-v5-qemu)), or uploaded to a physical device over a serial (USB) connection. +Binaries built for this target can be run in an emulator (such as [vex-v5-qemu](https://github.com/vexide/vex-v5-qemu)), or uploaded to a physical device over a USB serial connection. The default Rust test runner is not supported. @@ -110,7 +110,7 @@ The Rust test suite for `library/std` is not yet supported. This target can be cross-compiled from any host. -The recommended configuration for compiling compatible C code is via the [Arm Toolchain for Embedded](https://github.com/arm/arm-toolchain/tree/arm-software/arm-software/embedded#readme) the following compilation flags: +The recommended configuration for compiling compatible C code is to use the [Arm Toolchain for Embedded](https://github.com/arm/arm-toolchain/tree/arm-software/arm-software/embedded#readme) with the following compilation flags: ```sh clang --target=arm-none-eabi -mcpu=cortex-a9 -mfpu=neon -mfloat-abi=hard -fno-pic -fno-exceptions -fno-rtti -funwind-tables @@ -134,13 +134,13 @@ rustflags = [ # (or something custom): #"-Clink-arg=-nostartfiles", - # Explicit `-lc` required because Rust calls the linker with + # Explicit `-lc` required because Rust calls the linker with # `-nodefaultlibs` which disables libc, libm, etc. "-Clink-arg=-lc", ] ``` -You may also want to set these environment variables so that 3rd party crates use the correct C compiler: +You may also want to set these environment variables so that third-party crates use the correct C compiler: ```sh PATH=/path/to/arm-toolchain/bin:$PATH @@ -167,7 +167,7 @@ set(CMAKE_CXX_COMPILER_TARGET ${triple}) set(CMAKE_TRY_COMPILE_TARGET_TYPE "STATIC_LIBRARY") ``` -You can enable it by setting the following environment variable alongside the previously-mentioned environment variables: +You can enable it by setting the following environment variable alongside the previously mentioned environment variables: ```sh CMAKE_TOOLCHAIN_FILE_armv7a_vex_v5=/path/to/toolchain.cmake From 70af5cf2a3363ee8f37a611a398aec52f567910e Mon Sep 17 00:00:00 2001 From: Redddy Date: Tue, 7 Apr 2026 15:45:43 +0000 Subject: [PATCH 111/183] Move deref-patterns tests to pattern sub directory --- src/tools/tidy/src/issues.txt | 2 - tests/ui/README.md | 8 ---- tests/ui/deref-patterns/issue-71676-2.rs | 42 ------------------- tests/ui/deref-patterns/issue-71676-2.stderr | 18 -------- .../deref-patterns/deref-non-pointer.rs | 0 .../deref-patterns/deref-non-pointer.stderr | 0 ...deref-pointer-cast-mutability-71676.fixed} | 0 .../deref-pointer-cast-mutability-71676.rs} | 0 ...eref-pointer-cast-mutability-71676.stderr} | 0 9 files changed, 70 deletions(-) delete mode 100644 tests/ui/deref-patterns/issue-71676-2.rs delete mode 100644 tests/ui/deref-patterns/issue-71676-2.stderr rename tests/ui/{ => pattern}/deref-patterns/deref-non-pointer.rs (100%) rename tests/ui/{ => pattern}/deref-patterns/deref-non-pointer.stderr (100%) rename tests/ui/{deref-patterns/issue-71676-1.fixed => pattern/deref-patterns/deref-pointer-cast-mutability-71676.fixed} (100%) rename tests/ui/{deref-patterns/issue-71676-1.rs => pattern/deref-patterns/deref-pointer-cast-mutability-71676.rs} (100%) rename tests/ui/{deref-patterns/issue-71676-1.stderr => pattern/deref-patterns/deref-pointer-cast-mutability-71676.stderr} (100%) diff --git a/src/tools/tidy/src/issues.txt b/src/tools/tidy/src/issues.txt index 3b23fe5d80826..74b2a22451ae0 100644 --- a/src/tools/tidy/src/issues.txt +++ b/src/tools/tidy/src/issues.txt @@ -834,8 +834,6 @@ ui/cycle-trait/issue-12511.rs ui/debuginfo/issue-105386-debuginfo-ub.rs ui/deprecation/issue-66340-deprecated-attr-non-meta-grammar.rs ui/deprecation/issue-84637-deprecated-associated-function.rs -ui/deref-patterns/issue-71676-1.rs -ui/deref-patterns/issue-71676-2.rs ui/derived-errors/issue-30580.rs ui/derived-errors/issue-31997-1.rs ui/derived-errors/issue-31997.rs diff --git a/tests/ui/README.md b/tests/ui/README.md index a9e7f022c2b60..afe4ad97aef26 100644 --- a/tests/ui/README.md +++ b/tests/ui/README.md @@ -398,14 +398,6 @@ Tests for `#[deprecated]` attribute and `deprecated_in_future` internal lint. Tests for `Deref` and `DerefMut` traits. -## `tests/ui/deref-patterns`: `#![feature(deref_patterns)]` and `#![feature(string_deref_patterns)]` - -Tests for `#![feature(deref_patterns)]` and `#![feature(string_deref_patterns)]`. See [Deref patterns | The Unstable book](https://doc.rust-lang.org/nightly/unstable-book/language-features/deref-patterns.html). - -**FIXME**: May have some overlap with `tests/ui/pattern/deref-patterns`. - -See [`std::ops::Deref`](https://doc.rust-lang.org/std/ops/trait.Deref.html) and [`std::ops::DerefMut`](https://doc.rust-lang.org/std/ops/trait.DerefMut.html) - ## `tests/ui/derived-errors/`: Derived Error Messages Tests for quality of diagnostics involving suppression of cascading errors in some cases to avoid overwhelming the user. diff --git a/tests/ui/deref-patterns/issue-71676-2.rs b/tests/ui/deref-patterns/issue-71676-2.rs deleted file mode 100644 index f3183899dc523..0000000000000 --- a/tests/ui/deref-patterns/issue-71676-2.rs +++ /dev/null @@ -1,42 +0,0 @@ -use std::ops::Deref; -use std::ops::DerefMut; -struct Bar(u8); -struct Foo(Bar); -struct Emm(Foo); -impl Deref for Bar{ - type Target = u8; - fn deref(&self) -> &Self::Target { - &self.0 - } -} -impl Deref for Foo { - type Target = Bar; - fn deref(&self) -> &Self::Target { - &self.0 - } -} -impl Deref for Emm { - type Target = Foo; - fn deref(&self) -> &Self::Target { - &self.0 - } -} -impl DerefMut for Bar{ - fn deref_mut(&mut self) -> &mut Self::Target { - &mut self.0 - } -} -impl DerefMut for Foo { - fn deref_mut(&mut self) -> &mut Self::Target { - &mut self.0 - } -} -impl DerefMut for Emm { - fn deref_mut(&mut self) -> &mut Self::Target { - &mut self.0 - } -} -fn main() { - let a = Emm(Foo(Bar(0))); - let _: *mut u8 = &a; //~ ERROR mismatched types -} diff --git a/tests/ui/deref-patterns/issue-71676-2.stderr b/tests/ui/deref-patterns/issue-71676-2.stderr deleted file mode 100644 index 6ed318c8768b0..0000000000000 --- a/tests/ui/deref-patterns/issue-71676-2.stderr +++ /dev/null @@ -1,18 +0,0 @@ -error[E0308]: mismatched types - --> $DIR/issue-71676-2.rs:41:22 - | -LL | let _: *mut u8 = &a; - | ------- ^^ types differ in mutability - | | - | expected due to this - | - = note: expected raw pointer `*mut u8` - found reference `&Emm` -help: consider dereferencing - | -LL | let _: *mut u8 = &mut ***a; - | +++++++ - -error: aborting due to 1 previous error - -For more information about this error, try `rustc --explain E0308`. diff --git a/tests/ui/deref-patterns/deref-non-pointer.rs b/tests/ui/pattern/deref-patterns/deref-non-pointer.rs similarity index 100% rename from tests/ui/deref-patterns/deref-non-pointer.rs rename to tests/ui/pattern/deref-patterns/deref-non-pointer.rs diff --git a/tests/ui/deref-patterns/deref-non-pointer.stderr b/tests/ui/pattern/deref-patterns/deref-non-pointer.stderr similarity index 100% rename from tests/ui/deref-patterns/deref-non-pointer.stderr rename to tests/ui/pattern/deref-patterns/deref-non-pointer.stderr diff --git a/tests/ui/deref-patterns/issue-71676-1.fixed b/tests/ui/pattern/deref-patterns/deref-pointer-cast-mutability-71676.fixed similarity index 100% rename from tests/ui/deref-patterns/issue-71676-1.fixed rename to tests/ui/pattern/deref-patterns/deref-pointer-cast-mutability-71676.fixed diff --git a/tests/ui/deref-patterns/issue-71676-1.rs b/tests/ui/pattern/deref-patterns/deref-pointer-cast-mutability-71676.rs similarity index 100% rename from tests/ui/deref-patterns/issue-71676-1.rs rename to tests/ui/pattern/deref-patterns/deref-pointer-cast-mutability-71676.rs diff --git a/tests/ui/deref-patterns/issue-71676-1.stderr b/tests/ui/pattern/deref-patterns/deref-pointer-cast-mutability-71676.stderr similarity index 100% rename from tests/ui/deref-patterns/issue-71676-1.stderr rename to tests/ui/pattern/deref-patterns/deref-pointer-cast-mutability-71676.stderr From df2fe313d44bcc008331a0b01662cfdcaa0ecc90 Mon Sep 17 00:00:00 2001 From: Redddy Date: Tue, 7 Apr 2026 15:53:03 +0000 Subject: [PATCH 112/183] Fix format and bless test --- tests/ui/pattern/deref-patterns/deref-non-pointer.rs | 6 +++--- tests/ui/pattern/deref-patterns/deref-non-pointer.stderr | 6 +++--- .../deref-pointer-cast-mutability-71676.stderr | 8 ++++---- 3 files changed, 10 insertions(+), 10 deletions(-) diff --git a/tests/ui/pattern/deref-patterns/deref-non-pointer.rs b/tests/ui/pattern/deref-patterns/deref-non-pointer.rs index 82ab355e697b2..af9802481a6d0 100644 --- a/tests/ui/pattern/deref-patterns/deref-non-pointer.rs +++ b/tests/ui/pattern/deref-patterns/deref-non-pointer.rs @@ -1,5 +1,5 @@ fn main() { - match *1 { //~ ERROR: cannot be dereferenced - _ => { panic!(); } - } + match *1 { //~ ERROR: cannot be dereferenced + _ => {} + } } diff --git a/tests/ui/pattern/deref-patterns/deref-non-pointer.stderr b/tests/ui/pattern/deref-patterns/deref-non-pointer.stderr index 3ee354819e5d6..eae6c56a5e793 100644 --- a/tests/ui/pattern/deref-patterns/deref-non-pointer.stderr +++ b/tests/ui/pattern/deref-patterns/deref-non-pointer.stderr @@ -1,8 +1,8 @@ error[E0614]: type `{integer}` cannot be dereferenced - --> $DIR/deref-non-pointer.rs:2:9 + --> $DIR/deref-non-pointer.rs:2:11 | -LL | match *1 { - | ^^ can't be dereferenced +LL | match *1 { + | ^^ can't be dereferenced error: aborting due to 1 previous error diff --git a/tests/ui/pattern/deref-patterns/deref-pointer-cast-mutability-71676.stderr b/tests/ui/pattern/deref-patterns/deref-pointer-cast-mutability-71676.stderr index 348a2c12ec491..90675d1660f26 100644 --- a/tests/ui/pattern/deref-patterns/deref-pointer-cast-mutability-71676.stderr +++ b/tests/ui/pattern/deref-patterns/deref-pointer-cast-mutability-71676.stderr @@ -1,5 +1,5 @@ error[E0308]: mismatched types - --> $DIR/issue-71676-1.rs:43:24 + --> $DIR/deref-pointer-cast-mutability-71676.rs:43:24 | LL | let _: *const u8 = &a; | --------- ^^ expected `*const u8`, found `&Emm` @@ -14,7 +14,7 @@ LL | let _: *const u8 = &***a; | +++ error[E0308]: mismatched types - --> $DIR/issue-71676-1.rs:46:22 + --> $DIR/deref-pointer-cast-mutability-71676.rs:46:22 | LL | let _: *mut u8 = &a; | ------- ^^ types differ in mutability @@ -29,7 +29,7 @@ LL | let _: *mut u8 = &mut ***a; | +++++++ error[E0308]: mismatched types - --> $DIR/issue-71676-1.rs:49:24 + --> $DIR/deref-pointer-cast-mutability-71676.rs:49:24 | LL | let _: *const u8 = &mut a; | --------- ^^^^^^ expected `*const u8`, found `&mut Emm` @@ -45,7 +45,7 @@ LL + let _: *const u8 = &***a; | error[E0308]: mismatched types - --> $DIR/issue-71676-1.rs:52:22 + --> $DIR/deref-pointer-cast-mutability-71676.rs:52:22 | LL | let _: *mut u8 = &mut a; | ------- ^^^^^^ expected `*mut u8`, found `&mut Emm` From d2e978ea74a4b635e8496e323a4cff8c206b3f08 Mon Sep 17 00:00:00 2001 From: Redddy Date: Fri, 10 Apr 2026 03:38:21 +0000 Subject: [PATCH 113/183] Move unknown_lints tests into lint/unknown-lints dir --- src/tools/tidy/src/issues.txt | 2 -- tests/ui/README.md | 6 ------ .../allow-unknown-unstable-lint-command-line.rs | 0 .../allow-unknown-unstable-lint-inline.rs | 0 .../cli-unknown-force-warn.rs | 0 .../cli-unknown-force-warn.stderr | 0 .../deny-unstable-lint-command-line.rs | 1 - .../deny-unstable-lint-command-line.stderr | 0 .../unknown-lints}/deny-unstable-lint-inline.rs | 2 -- .../deny-unstable-lint-inline.stderr | 4 ++-- .../redundant-path-83477.rs} | 0 .../redundant-path-83477.stderr} | 8 ++++---- .../suggestions.rs} | 3 +++ .../suggestions.stderr} | 14 ++++++++++---- .../unknown-lints-in-cfg-attr-97094.rs} | 0 .../unknown-lints-in-cfg-attr-97094.stderr} | 16 ++++++++-------- .../warn-unknown-unstable-lint-command-line.rs | 0 ...arn-unknown-unstable-lint-command-line.stderr | 0 .../warn-unknown-unstable-lint-inline.rs | 0 .../warn-unknown-unstable-lint-inline.stderr | 0 20 files changed, 27 insertions(+), 29 deletions(-) rename tests/ui/{unknown-unstable-lints => lint/unknown-lints}/allow-unknown-unstable-lint-command-line.rs (100%) rename tests/ui/{unknown-unstable-lints => lint/unknown-lints}/allow-unknown-unstable-lint-inline.rs (100%) rename tests/ui/lint/{ => unknown-lints}/cli-unknown-force-warn.rs (100%) rename tests/ui/lint/{ => unknown-lints}/cli-unknown-force-warn.stderr (100%) rename tests/ui/{unknown-unstable-lints => lint/unknown-lints}/deny-unstable-lint-command-line.rs (93%) rename tests/ui/{unknown-unstable-lints => lint/unknown-lints}/deny-unstable-lint-command-line.stderr (100%) rename tests/ui/{unknown-unstable-lints => lint/unknown-lints}/deny-unstable-lint-inline.rs (87%) rename tests/ui/{unknown-unstable-lints => lint/unknown-lints}/deny-unstable-lint-inline.stderr (84%) rename tests/ui/lint/{issue-83477.rs => unknown-lints/redundant-path-83477.rs} (100%) rename tests/ui/lint/{issue-83477.stderr => unknown-lints/redundant-path-83477.stderr} (86%) rename tests/ui/lint/{not_found.rs => unknown-lints/suggestions.rs} (82%) rename tests/ui/lint/{not_found.stderr => unknown-lints/suggestions.stderr} (57%) rename tests/ui/lint/{issue-97094.rs => unknown-lints/unknown-lints-in-cfg-attr-97094.rs} (100%) rename tests/ui/lint/{issue-97094.stderr => unknown-lints/unknown-lints-in-cfg-attr-97094.stderr} (76%) rename tests/ui/{unknown-unstable-lints => lint/unknown-lints}/warn-unknown-unstable-lint-command-line.rs (100%) rename tests/ui/{unknown-unstable-lints => lint/unknown-lints}/warn-unknown-unstable-lint-command-line.stderr (100%) rename tests/ui/{unknown-unstable-lints => lint/unknown-lints}/warn-unknown-unstable-lint-inline.rs (100%) rename tests/ui/{unknown-unstable-lints => lint/unknown-lints}/warn-unknown-unstable-lint-inline.stderr (100%) diff --git a/src/tools/tidy/src/issues.txt b/src/tools/tidy/src/issues.txt index 74b2a22451ae0..7e471a102d1d9 100644 --- a/src/tools/tidy/src/issues.txt +++ b/src/tools/tidy/src/issues.txt @@ -1463,10 +1463,8 @@ ui/lint/issue-63364.rs ui/lint/issue-70819-dont-override-forbid-in-same-scope.rs ui/lint/issue-79744.rs ui/lint/issue-81218.rs -ui/lint/issue-83477.rs ui/lint/issue-87274-paren-parent.rs ui/lint/issue-90614-accept-allow-text-direction-codepoint-in-comment-lint.rs -ui/lint/issue-97094.rs ui/lint/issue-99387.rs ui/lint/let_underscore/issue-119696-err-on-fn.rs ui/lint/let_underscore/issue-119697-extra-let.rs diff --git a/tests/ui/README.md b/tests/ui/README.md index afe4ad97aef26..946f32bf0e9ac 100644 --- a/tests/ui/README.md +++ b/tests/ui/README.md @@ -1492,12 +1492,6 @@ See [Uninhabited | Reference](https://doc.rust-lang.org/reference/glossary.html? See [Unions | Reference](https://doc.rust-lang.org/reference/items/unions.html). -## `tests/ui/unknown-unstable-lints/`: Attempting to refer to an unstable lint which does not exist - -Tests for trying to use non-existent unstable lints. - -**FIXME**: move this under `tests/ui/lints/`. - ## `tests/ui/unop/`: Unary operators `-`, `*` and `!` Tests the three unary operators for negating, dereferencing and inverting, across different contexts. diff --git a/tests/ui/unknown-unstable-lints/allow-unknown-unstable-lint-command-line.rs b/tests/ui/lint/unknown-lints/allow-unknown-unstable-lint-command-line.rs similarity index 100% rename from tests/ui/unknown-unstable-lints/allow-unknown-unstable-lint-command-line.rs rename to tests/ui/lint/unknown-lints/allow-unknown-unstable-lint-command-line.rs diff --git a/tests/ui/unknown-unstable-lints/allow-unknown-unstable-lint-inline.rs b/tests/ui/lint/unknown-lints/allow-unknown-unstable-lint-inline.rs similarity index 100% rename from tests/ui/unknown-unstable-lints/allow-unknown-unstable-lint-inline.rs rename to tests/ui/lint/unknown-lints/allow-unknown-unstable-lint-inline.rs diff --git a/tests/ui/lint/cli-unknown-force-warn.rs b/tests/ui/lint/unknown-lints/cli-unknown-force-warn.rs similarity index 100% rename from tests/ui/lint/cli-unknown-force-warn.rs rename to tests/ui/lint/unknown-lints/cli-unknown-force-warn.rs diff --git a/tests/ui/lint/cli-unknown-force-warn.stderr b/tests/ui/lint/unknown-lints/cli-unknown-force-warn.stderr similarity index 100% rename from tests/ui/lint/cli-unknown-force-warn.stderr rename to tests/ui/lint/unknown-lints/cli-unknown-force-warn.stderr diff --git a/tests/ui/unknown-unstable-lints/deny-unstable-lint-command-line.rs b/tests/ui/lint/unknown-lints/deny-unstable-lint-command-line.rs similarity index 93% rename from tests/ui/unknown-unstable-lints/deny-unstable-lint-command-line.rs rename to tests/ui/lint/unknown-lints/deny-unstable-lint-command-line.rs index 6005bc96ad6d1..bad7b37b56c7d 100644 --- a/tests/ui/unknown-unstable-lints/deny-unstable-lint-command-line.rs +++ b/tests/ui/lint/unknown-lints/deny-unstable-lint-command-line.rs @@ -1,6 +1,5 @@ //~ ERROR unknown lint: `test_unstable_lint` //~^ NOTE the `test_unstable_lint` lint is unstable -//@ check-fail //@ compile-flags: -Dunknown_lints -Atest_unstable_lint //@ dont-require-annotations: NOTE diff --git a/tests/ui/unknown-unstable-lints/deny-unstable-lint-command-line.stderr b/tests/ui/lint/unknown-lints/deny-unstable-lint-command-line.stderr similarity index 100% rename from tests/ui/unknown-unstable-lints/deny-unstable-lint-command-line.stderr rename to tests/ui/lint/unknown-lints/deny-unstable-lint-command-line.stderr diff --git a/tests/ui/unknown-unstable-lints/deny-unstable-lint-inline.rs b/tests/ui/lint/unknown-lints/deny-unstable-lint-inline.rs similarity index 87% rename from tests/ui/unknown-unstable-lints/deny-unstable-lint-inline.rs rename to tests/ui/lint/unknown-lints/deny-unstable-lint-inline.rs index a13c92151ac9c..623e639e7a00d 100644 --- a/tests/ui/unknown-unstable-lints/deny-unstable-lint-inline.rs +++ b/tests/ui/lint/unknown-lints/deny-unstable-lint-inline.rs @@ -1,5 +1,3 @@ -//@ check-fail - #![deny(unknown_lints)] #![allow(test_unstable_lint)] //~^ ERROR unknown lint: `test_unstable_lint` diff --git a/tests/ui/unknown-unstable-lints/deny-unstable-lint-inline.stderr b/tests/ui/lint/unknown-lints/deny-unstable-lint-inline.stderr similarity index 84% rename from tests/ui/unknown-unstable-lints/deny-unstable-lint-inline.stderr rename to tests/ui/lint/unknown-lints/deny-unstable-lint-inline.stderr index 4ff909453979a..4b04c97810f81 100644 --- a/tests/ui/unknown-unstable-lints/deny-unstable-lint-inline.stderr +++ b/tests/ui/lint/unknown-lints/deny-unstable-lint-inline.stderr @@ -1,5 +1,5 @@ error: unknown lint: `test_unstable_lint` - --> $DIR/deny-unstable-lint-inline.rs:4:10 + --> $DIR/deny-unstable-lint-inline.rs:2:10 | LL | #![allow(test_unstable_lint)] | ^^^^^^^^^^^^^^^^^^ @@ -8,7 +8,7 @@ LL | #![allow(test_unstable_lint)] = help: add `#![feature(test_unstable_lint)]` to the crate attributes to enable = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date note: the lint level is defined here - --> $DIR/deny-unstable-lint-inline.rs:3:9 + --> $DIR/deny-unstable-lint-inline.rs:1:9 | LL | #![deny(unknown_lints)] | ^^^^^^^^^^^^^ diff --git a/tests/ui/lint/issue-83477.rs b/tests/ui/lint/unknown-lints/redundant-path-83477.rs similarity index 100% rename from tests/ui/lint/issue-83477.rs rename to tests/ui/lint/unknown-lints/redundant-path-83477.rs diff --git a/tests/ui/lint/issue-83477.stderr b/tests/ui/lint/unknown-lints/redundant-path-83477.stderr similarity index 86% rename from tests/ui/lint/issue-83477.stderr rename to tests/ui/lint/unknown-lints/redundant-path-83477.stderr index f824fc09e7240..8e25bd7136be8 100644 --- a/tests/ui/lint/issue-83477.stderr +++ b/tests/ui/lint/unknown-lints/redundant-path-83477.stderr @@ -1,5 +1,5 @@ warning: unknown lint: `rustc::foo::bar::default_hash_types` - --> $DIR/issue-83477.rs:5:9 + --> $DIR/redundant-path-83477.rs:5:9 | LL | #[allow(rustc::foo::bar::default_hash_types)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: did you mean: `rustc::default_hash_types` @@ -7,20 +7,20 @@ LL | #[allow(rustc::foo::bar::default_hash_types)] = note: `#[warn(unknown_lints)]` on by default warning: unknown lint: `rustc::foo::default_hash_types` - --> $DIR/issue-83477.rs:9:9 + --> $DIR/redundant-path-83477.rs:9:9 | LL | #[allow(rustc::foo::default_hash_types)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: did you mean: `rustc::default_hash_types` warning: prefer `FxHashMap` over `HashMap`, it has better performance - --> $DIR/issue-83477.rs:14:13 + --> $DIR/redundant-path-83477.rs:14:13 | LL | let _ = std::collections::HashMap::::new(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: a `use rustc_data_structures::fx::FxHashMap` may be necessary note: the lint level is defined here - --> $DIR/issue-83477.rs:3:9 + --> $DIR/redundant-path-83477.rs:3:9 | LL | #![warn(rustc::internal)] | ^^^^^^^^^^^^^^^ diff --git a/tests/ui/lint/not_found.rs b/tests/ui/lint/unknown-lints/suggestions.rs similarity index 82% rename from tests/ui/lint/not_found.rs rename to tests/ui/lint/unknown-lints/suggestions.rs index 8e79c6da15273..72e688f70f31a 100644 --- a/tests/ui/lint/not_found.rs +++ b/tests/ui/lint/unknown-lints/suggestions.rs @@ -16,6 +16,9 @@ //~^ WARNING unknown lint //~| HELP did you mean +#[deny(rust_2018_idiots)] //~ WARNING unknown lint + //~| HELP did you mean + fn main() { unimplemented!(); } diff --git a/tests/ui/lint/not_found.stderr b/tests/ui/lint/unknown-lints/suggestions.stderr similarity index 57% rename from tests/ui/lint/not_found.stderr rename to tests/ui/lint/unknown-lints/suggestions.stderr index ea118c73ce784..322d605753416 100644 --- a/tests/ui/lint/not_found.stderr +++ b/tests/ui/lint/unknown-lints/suggestions.stderr @@ -1,5 +1,5 @@ warning: unknown lint: `FOO_BAR` - --> $DIR/not_found.rs:6:9 + --> $DIR/suggestions.rs:6:9 | LL | #[allow(FOO_BAR)] | ^^^^^^^ @@ -7,16 +7,22 @@ LL | #[allow(FOO_BAR)] = note: `#[warn(unknown_lints)]` on by default warning: unknown lint: `DEAD_CODE` - --> $DIR/not_found.rs:10:8 + --> $DIR/suggestions.rs:10:8 | LL | #[warn(DEAD_CODE)] | ^^^^^^^^^ help: did you mean: `dead_code` warning: unknown lint: `Warnings` - --> $DIR/not_found.rs:15:8 + --> $DIR/suggestions.rs:15:8 | LL | #[deny(Warnings)] | ^^^^^^^^ help: did you mean (notice the capitalization): `warnings` -warning: 3 warnings emitted +warning: unknown lint: `rust_2018_idiots` + --> $DIR/suggestions.rs:19:8 + | +LL | #[deny(rust_2018_idiots)] + | ^^^^^^^^^^^^^^^^ help: did you mean: `rust_2018_idioms` + +warning: 4 warnings emitted diff --git a/tests/ui/lint/issue-97094.rs b/tests/ui/lint/unknown-lints/unknown-lints-in-cfg-attr-97094.rs similarity index 100% rename from tests/ui/lint/issue-97094.rs rename to tests/ui/lint/unknown-lints/unknown-lints-in-cfg-attr-97094.rs diff --git a/tests/ui/lint/issue-97094.stderr b/tests/ui/lint/unknown-lints/unknown-lints-in-cfg-attr-97094.stderr similarity index 76% rename from tests/ui/lint/issue-97094.stderr rename to tests/ui/lint/unknown-lints/unknown-lints-in-cfg-attr-97094.stderr index e12250aa7542e..3309fa2c443d8 100644 --- a/tests/ui/lint/issue-97094.stderr +++ b/tests/ui/lint/unknown-lints/unknown-lints-in-cfg-attr-97094.stderr @@ -1,18 +1,18 @@ error: unknown lint: `nonex_lint_top_level` - --> $DIR/issue-97094.rs:5:25 + --> $DIR/unknown-lints-in-cfg-attr-97094.rs:5:25 | LL | #![cfg_attr(true, allow(nonex_lint_top_level))] | ^^^^^^^^^^^^^^^^^^^^ | note: the lint level is defined here - --> $DIR/issue-97094.rs:1:9 + --> $DIR/unknown-lints-in-cfg-attr-97094.rs:1:9 | LL | #![deny(warnings)] | ^^^^^^^^ = note: `#[deny(unknown_lints)]` implied by `#[deny(warnings)]` error: lint `bare_trait_object` has been renamed to `bare_trait_objects` - --> $DIR/issue-97094.rs:7:25 + --> $DIR/unknown-lints-in-cfg-attr-97094.rs:7:25 | LL | #![cfg_attr(true, allow(bare_trait_object))] | ^^^^^^^^^^^^^^^^^ help: use the new name: `bare_trait_objects` @@ -20,31 +20,31 @@ LL | #![cfg_attr(true, allow(bare_trait_object))] = note: `#[deny(renamed_and_removed_lints)]` implied by `#[deny(warnings)]` error: unknown lint: `nonex_lint_mod` - --> $DIR/issue-97094.rs:10:24 + --> $DIR/unknown-lints-in-cfg-attr-97094.rs:10:24 | LL | #[cfg_attr(true, allow(nonex_lint_mod))] | ^^^^^^^^^^^^^^ error: unknown lint: `nonex_lint_mod_inner` - --> $DIR/issue-97094.rs:13:29 + --> $DIR/unknown-lints-in-cfg-attr-97094.rs:13:29 | LL | #![cfg_attr(true, allow(nonex_lint_mod_inner))] | ^^^^^^^^^^^^^^^^^^^^ error: unknown lint: `nonex_lint_fn` - --> $DIR/issue-97094.rs:17:24 + --> $DIR/unknown-lints-in-cfg-attr-97094.rs:17:24 | LL | #[cfg_attr(true, allow(nonex_lint_fn))] | ^^^^^^^^^^^^^ error: unknown lint: `nonex_lint_in_macro` - --> $DIR/issue-97094.rs:28:28 + --> $DIR/unknown-lints-in-cfg-attr-97094.rs:28:28 | LL | #[cfg_attr(true, allow(nonex_lint_in_macro))] | ^^^^^^^^^^^^^^^^^^^ error: unknown lint: `nonex_lint_fn` - --> $DIR/issue-97094.rs:47:13 + --> $DIR/unknown-lints-in-cfg-attr-97094.rs:47:13 | LL | #[allow(nonex_lint_fn)] | ^^^^^^^^^^^^^ diff --git a/tests/ui/unknown-unstable-lints/warn-unknown-unstable-lint-command-line.rs b/tests/ui/lint/unknown-lints/warn-unknown-unstable-lint-command-line.rs similarity index 100% rename from tests/ui/unknown-unstable-lints/warn-unknown-unstable-lint-command-line.rs rename to tests/ui/lint/unknown-lints/warn-unknown-unstable-lint-command-line.rs diff --git a/tests/ui/unknown-unstable-lints/warn-unknown-unstable-lint-command-line.stderr b/tests/ui/lint/unknown-lints/warn-unknown-unstable-lint-command-line.stderr similarity index 100% rename from tests/ui/unknown-unstable-lints/warn-unknown-unstable-lint-command-line.stderr rename to tests/ui/lint/unknown-lints/warn-unknown-unstable-lint-command-line.stderr diff --git a/tests/ui/unknown-unstable-lints/warn-unknown-unstable-lint-inline.rs b/tests/ui/lint/unknown-lints/warn-unknown-unstable-lint-inline.rs similarity index 100% rename from tests/ui/unknown-unstable-lints/warn-unknown-unstable-lint-inline.rs rename to tests/ui/lint/unknown-lints/warn-unknown-unstable-lint-inline.rs diff --git a/tests/ui/unknown-unstable-lints/warn-unknown-unstable-lint-inline.stderr b/tests/ui/lint/unknown-lints/warn-unknown-unstable-lint-inline.stderr similarity index 100% rename from tests/ui/unknown-unstable-lints/warn-unknown-unstable-lint-inline.stderr rename to tests/ui/lint/unknown-lints/warn-unknown-unstable-lint-inline.stderr From e110275cce45886a386b5e2dd8e84aef7ab05a4a Mon Sep 17 00:00:00 2001 From: Redddy Date: Fri, 10 Apr 2026 04:20:36 +0000 Subject: [PATCH 114/183] Clean up unknown-lints ui tests --- .../lint/lint-unknown-lint-cmdline-allow.rs | 4 --- .../ui/lint/lint-unknown-lint-cmdline-deny.rs | 16 --------- .../lint-unknown-lint-cmdline-deny.stderr | 35 ------------------- tests/ui/lint/lint-unknown-lint-cmdline.rs | 17 --------- .../ui/lint/lint-unknown-lint-cmdline.stderr | 35 ------------------- tests/ui/lint/lint-unknown-lint.rs | 13 ------- tests/ui/lint/lint-unknown-lint.stderr | 26 -------------- tests/ui/lint/unknown-lints-at-crate-level.rs | 7 ---- 8 files changed, 153 deletions(-) delete mode 100644 tests/ui/lint/lint-unknown-lint-cmdline-allow.rs delete mode 100644 tests/ui/lint/lint-unknown-lint-cmdline-deny.rs delete mode 100644 tests/ui/lint/lint-unknown-lint-cmdline-deny.stderr delete mode 100644 tests/ui/lint/lint-unknown-lint-cmdline.rs delete mode 100644 tests/ui/lint/lint-unknown-lint-cmdline.stderr delete mode 100644 tests/ui/lint/lint-unknown-lint.rs delete mode 100644 tests/ui/lint/lint-unknown-lint.stderr delete mode 100644 tests/ui/lint/unknown-lints-at-crate-level.rs diff --git a/tests/ui/lint/lint-unknown-lint-cmdline-allow.rs b/tests/ui/lint/lint-unknown-lint-cmdline-allow.rs deleted file mode 100644 index 68c5e3b1a3a08..0000000000000 --- a/tests/ui/lint/lint-unknown-lint-cmdline-allow.rs +++ /dev/null @@ -1,4 +0,0 @@ -//@ check-pass -//@ compile-flags:-A unknown-lints -D bogus -D dead_cod - -fn main() { } diff --git a/tests/ui/lint/lint-unknown-lint-cmdline-deny.rs b/tests/ui/lint/lint-unknown-lint-cmdline-deny.rs deleted file mode 100644 index ac001e1b6a04d..0000000000000 --- a/tests/ui/lint/lint-unknown-lint-cmdline-deny.rs +++ /dev/null @@ -1,16 +0,0 @@ -//@ compile-flags:-D unknown-lints -D bogus -D dead_cod -//@ dont-require-annotations: HELP -//@ dont-require-annotations: NOTE - -fn main() { } - -//~? ERROR unknown lint: `bogus` -//~? ERROR unknown lint: `dead_cod` -//~? ERROR unknown lint: `bogus` -//~? ERROR unknown lint: `dead_cod` -//~? ERROR unknown lint: `bogus` -//~? ERROR unknown lint: `dead_cod` -//~? NOTE requested on the command line with `-D bogus` -//~? NOTE requested on the command line with `-D dead_cod` -//~? NOTE requested on the command line with `-D unknown-lints` -//~? HELP did you mean: `dead_code` diff --git a/tests/ui/lint/lint-unknown-lint-cmdline-deny.stderr b/tests/ui/lint/lint-unknown-lint-cmdline-deny.stderr deleted file mode 100644 index f12ce03ddfcef..0000000000000 --- a/tests/ui/lint/lint-unknown-lint-cmdline-deny.stderr +++ /dev/null @@ -1,35 +0,0 @@ -error[E0602]: unknown lint: `bogus` - | - = note: requested on the command line with `-D bogus` - = note: requested on the command line with `-D unknown-lints` - -error[E0602]: unknown lint: `dead_cod` - | - = help: did you mean: `dead_code` - = note: requested on the command line with `-D dead_cod` - -error[E0602]: unknown lint: `bogus` - | - = note: requested on the command line with `-D bogus` - = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` - -error[E0602]: unknown lint: `dead_cod` - | - = help: did you mean: `dead_code` - = note: requested on the command line with `-D dead_cod` - = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` - -error[E0602]: unknown lint: `bogus` - | - = note: requested on the command line with `-D bogus` - = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` - -error[E0602]: unknown lint: `dead_cod` - | - = help: did you mean: `dead_code` - = note: requested on the command line with `-D dead_cod` - = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` - -error: aborting due to 6 previous errors - -For more information about this error, try `rustc --explain E0602`. diff --git a/tests/ui/lint/lint-unknown-lint-cmdline.rs b/tests/ui/lint/lint-unknown-lint-cmdline.rs deleted file mode 100644 index 7eb8c1f73142f..0000000000000 --- a/tests/ui/lint/lint-unknown-lint-cmdline.rs +++ /dev/null @@ -1,17 +0,0 @@ -//@ check-pass -//@ compile-flags:-D bogus -D dead_cod -//@ dont-require-annotations: HELP -//@ dont-require-annotations: NOTE - -fn main() { } - -//~? WARN unknown lint: `bogus` -//~? WARN unknown lint: `dead_cod` -//~? WARN unknown lint: `bogus` -//~? WARN unknown lint: `dead_cod` -//~? WARN unknown lint: `bogus` -//~? WARN unknown lint: `dead_cod` -//~? NOTE requested on the command line with `-D bogus` -//~? NOTE `#[warn(unknown_lints)]` on by default -//~? NOTE requested on the command line with `-D dead_cod` -//~? HELP did you mean: `dead_code` diff --git a/tests/ui/lint/lint-unknown-lint-cmdline.stderr b/tests/ui/lint/lint-unknown-lint-cmdline.stderr deleted file mode 100644 index f452fc9eb943c..0000000000000 --- a/tests/ui/lint/lint-unknown-lint-cmdline.stderr +++ /dev/null @@ -1,35 +0,0 @@ -warning[E0602]: unknown lint: `bogus` - | - = note: requested on the command line with `-D bogus` - = note: `#[warn(unknown_lints)]` on by default - -warning[E0602]: unknown lint: `dead_cod` - | - = help: did you mean: `dead_code` - = note: requested on the command line with `-D dead_cod` - -warning[E0602]: unknown lint: `bogus` - | - = note: requested on the command line with `-D bogus` - = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` - -warning[E0602]: unknown lint: `dead_cod` - | - = help: did you mean: `dead_code` - = note: requested on the command line with `-D dead_cod` - = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` - -warning[E0602]: unknown lint: `bogus` - | - = note: requested on the command line with `-D bogus` - = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` - -warning[E0602]: unknown lint: `dead_cod` - | - = help: did you mean: `dead_code` - = note: requested on the command line with `-D dead_cod` - = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` - -warning: 6 warnings emitted - -For more information about this error, try `rustc --explain E0602`. diff --git a/tests/ui/lint/lint-unknown-lint.rs b/tests/ui/lint/lint-unknown-lint.rs deleted file mode 100644 index 2d842d5142097..0000000000000 --- a/tests/ui/lint/lint-unknown-lint.rs +++ /dev/null @@ -1,13 +0,0 @@ -#![deny(unknown_lints)] - -#![allow(not_a_real_lint)] //~ ERROR unknown lint - -#![deny(dead_cod)] //~ ERROR unknown lint - //~| HELP did you mean - //~| SUGGESTION dead_code - -#![deny(rust_2018_idiots)] //~ ERROR unknown lint - //~| HELP did you mean - //~| SUGGESTION rust_2018_idioms - -fn main() {} diff --git a/tests/ui/lint/lint-unknown-lint.stderr b/tests/ui/lint/lint-unknown-lint.stderr deleted file mode 100644 index 0cb6b49578cf3..0000000000000 --- a/tests/ui/lint/lint-unknown-lint.stderr +++ /dev/null @@ -1,26 +0,0 @@ -error: unknown lint: `not_a_real_lint` - --> $DIR/lint-unknown-lint.rs:3:10 - | -LL | #![allow(not_a_real_lint)] - | ^^^^^^^^^^^^^^^ - | -note: the lint level is defined here - --> $DIR/lint-unknown-lint.rs:1:9 - | -LL | #![deny(unknown_lints)] - | ^^^^^^^^^^^^^ - -error: unknown lint: `dead_cod` - --> $DIR/lint-unknown-lint.rs:5:9 - | -LL | #![deny(dead_cod)] - | ^^^^^^^^ help: did you mean: `dead_code` - -error: unknown lint: `rust_2018_idiots` - --> $DIR/lint-unknown-lint.rs:9:9 - | -LL | #![deny(rust_2018_idiots)] - | ^^^^^^^^^^^^^^^^ help: did you mean: `rust_2018_idioms` - -error: aborting due to 3 previous errors - diff --git a/tests/ui/lint/unknown-lints-at-crate-level.rs b/tests/ui/lint/unknown-lints-at-crate-level.rs deleted file mode 100644 index c8cf65ce93a9a..0000000000000 --- a/tests/ui/lint/unknown-lints-at-crate-level.rs +++ /dev/null @@ -1,7 +0,0 @@ -//@ run-pass -//@ compile-flags: -D warnings -D unknown-lints - -#![allow(unknown_lints)] -#![allow(random_lint_name)] - -fn main() {} From 7c23ee6fcaf9357757fb087ec705ddd17de7550d Mon Sep 17 00:00:00 2001 From: Redddy Date: Fri, 10 Apr 2026 05:05:59 +0000 Subject: [PATCH 115/183] Move reserved tests to keyword --- tests/ui/README.md | 8 -------- tests/ui/{reserved => keyword}/meta-is-not-reserved.rs | 0 .../ui/{reserved => keyword}/meta-is-not-reserved.stderr | 0 tests/ui/{reserved => keyword}/reserved-attr-on-macro.rs | 0 .../{reserved => keyword}/reserved-attr-on-macro.stderr | 0 tests/ui/{reserved => keyword}/reserved-become.rs | 0 tests/ui/{reserved => keyword}/reserved-become.stderr | 0 7 files changed, 8 deletions(-) rename tests/ui/{reserved => keyword}/meta-is-not-reserved.rs (100%) rename tests/ui/{reserved => keyword}/meta-is-not-reserved.stderr (100%) rename tests/ui/{reserved => keyword}/reserved-attr-on-macro.rs (100%) rename tests/ui/{reserved => keyword}/reserved-attr-on-macro.stderr (100%) rename tests/ui/{reserved => keyword}/reserved-become.rs (100%) rename tests/ui/{reserved => keyword}/reserved-become.stderr (100%) diff --git a/tests/ui/README.md b/tests/ui/README.md index 946f32bf0e9ac..1f49b2d6ce5e6 100644 --- a/tests/ui/README.md +++ b/tests/ui/README.md @@ -1158,14 +1158,6 @@ Exercises `[Type; n]` syntax for creating arrays with repeated types across a se Tests on the `#[repr(..)]` attribute. See [Representations | Reference](https://doc.rust-lang.org/reference/type-layout.html#representations). -## `tests/ui/reserved/` - -Reserved keywords and attribute names. - -See e.g. [Reserved keywords | Reference](https://doc.rust-lang.org/reference/keywords.html). - -**FIXME**: maybe merge under `tests/ui/keyword/`. - ## `tests/ui/resolve/`: Name resolution See [Name resolution | rustc-dev-guide](https://rustc-dev-guide.rust-lang.org/name-resolution.html). diff --git a/tests/ui/reserved/meta-is-not-reserved.rs b/tests/ui/keyword/meta-is-not-reserved.rs similarity index 100% rename from tests/ui/reserved/meta-is-not-reserved.rs rename to tests/ui/keyword/meta-is-not-reserved.rs diff --git a/tests/ui/reserved/meta-is-not-reserved.stderr b/tests/ui/keyword/meta-is-not-reserved.stderr similarity index 100% rename from tests/ui/reserved/meta-is-not-reserved.stderr rename to tests/ui/keyword/meta-is-not-reserved.stderr diff --git a/tests/ui/reserved/reserved-attr-on-macro.rs b/tests/ui/keyword/reserved-attr-on-macro.rs similarity index 100% rename from tests/ui/reserved/reserved-attr-on-macro.rs rename to tests/ui/keyword/reserved-attr-on-macro.rs diff --git a/tests/ui/reserved/reserved-attr-on-macro.stderr b/tests/ui/keyword/reserved-attr-on-macro.stderr similarity index 100% rename from tests/ui/reserved/reserved-attr-on-macro.stderr rename to tests/ui/keyword/reserved-attr-on-macro.stderr diff --git a/tests/ui/reserved/reserved-become.rs b/tests/ui/keyword/reserved-become.rs similarity index 100% rename from tests/ui/reserved/reserved-become.rs rename to tests/ui/keyword/reserved-become.rs diff --git a/tests/ui/reserved/reserved-become.stderr b/tests/ui/keyword/reserved-become.stderr similarity index 100% rename from tests/ui/reserved/reserved-become.stderr rename to tests/ui/keyword/reserved-become.stderr From 3af9faa6cd8af55c0a6aff2be84d275a91863684 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Mon, 23 Mar 2026 12:12:34 -0500 Subject: [PATCH 116/183] test: Move `tidy_lists` from `update-api-list.py` to a new crate This is the first step of migrating `update-api-list.py` to something that handles the compiler-builtins functions. --- .../.github/workflows/main.yaml | 5 +- library/compiler-builtins/Cargo.lock | 39 ++++++ library/compiler-builtins/Cargo.toml | 3 + library/compiler-builtins/ci/run.sh | 2 +- .../crates/update-api-list/Cargo.toml | 13 ++ .../crates/update-api-list/src/lib.rs | 11 ++ .../crates/update-api-list/tests/all.rs | 128 ++++++++++++++++++ .../compiler-builtins/etc/update-api-list.py | 82 +---------- 8 files changed, 200 insertions(+), 83 deletions(-) create mode 100644 library/compiler-builtins/crates/update-api-list/Cargo.toml create mode 100644 library/compiler-builtins/crates/update-api-list/src/lib.rs create mode 100644 library/compiler-builtins/crates/update-api-list/tests/all.rs diff --git a/library/compiler-builtins/.github/workflows/main.yaml b/library/compiler-builtins/.github/workflows/main.yaml index 39aab42a3950a..aba86eaa93edd 100644 --- a/library/compiler-builtins/.github/workflows/main.yaml +++ b/library/compiler-builtins/.github/workflows/main.yaml @@ -181,7 +181,10 @@ jobs: - name: Verify API list if: matrix.os == 'ubuntu-24.04' || contains(matrix.os, 'self-hosted') - run: python3 etc/update-api-list.py --check + run: | + # Must be run on the host (not in Docker) because git and fs access is required. + python3 etc/update-api-list.py --check + cargo test -p update-api-list # Non-linux tests just use our raw script - name: Run locally diff --git a/library/compiler-builtins/Cargo.lock b/library/compiler-builtins/Cargo.lock index fbfb62ede17a2..7a3e580f4e6b1 100644 --- a/library/compiler-builtins/Cargo.lock +++ b/library/compiler-builtins/Cargo.lock @@ -391,6 +391,12 @@ dependencies = [ "syn", ] +[[package]] +name = "diff" +version = "0.1.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "56254986775e3233ffa9c4d7d3faaf6d36a2c09d30b20687e9f88bc8bafc16c8" + [[package]] name = "difflib" version = "0.4.0" @@ -484,6 +490,12 @@ dependencies = [ "wasm-bindgen", ] +[[package]] +name = "glob" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0cc23270f6e1808e30a928bdc84dea0b9b4136a8bc82338574f23baf47bbd280" + [[package]] name = "gmp-mpfr-sys" version = "1.7.0" @@ -871,6 +883,16 @@ dependencies = [ "termtree", ] +[[package]] +name = "pretty_assertions" +version = "1.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3ae130e2f271fbc2ac3a40fb1d07180839cdbbe443c7a27e1e3c13c5cac0116d" +dependencies = [ + "diff", + "yansi", +] + [[package]] name = "prettyplease" version = "0.2.37" @@ -1236,6 +1258,17 @@ version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "81e544489bf3d8ef66c953931f56617f423cd4b5494be343d9b9d3dda037b9a3" +[[package]] +name = "update-api-list" +version = "0.1.0" +dependencies = [ + "api-list-common", + "getopts", + "glob", + "pretty_assertions", + "regex", +] + [[package]] name = "utf8parse" version = "0.2.2" @@ -1533,6 +1566,12 @@ dependencies = [ "wasmparser 0.244.0", ] +[[package]] +name = "yansi" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cfe53a6657fd280eaa890a3bc59152892ffa3e30101319d168b781ed6529b049" + [[package]] name = "zerocopy" version = "0.8.48" diff --git a/library/compiler-builtins/Cargo.toml b/library/compiler-builtins/Cargo.toml index 8f65394c782c7..a925939d53567 100644 --- a/library/compiler-builtins/Cargo.toml +++ b/library/compiler-builtins/Cargo.toml @@ -8,6 +8,7 @@ members = [ "crates/musl-math-sys", "crates/panic-handler", "crates/symbol-check", + "crates/update-api-list", "crates/util", "libm", "libm-test", @@ -43,6 +44,7 @@ compiler_builtins = { path = "builtins-shim", default-features = false } criterion = { version = "0.8.2", default-features = false, features = ["cargo_bench_support"] } getopts = "0.2.24" getrandom = "0.4.1" +glob = "0.3.3" gmp-mpfr-sys = { version = "1.6.8", default-features = false } gungraun = "0.17.2" heck = "0.5.0" @@ -56,6 +58,7 @@ no-panic = "0.1.36" object = { version = "0.39.0", features = ["wasm"] } panic-handler = { path = "crates/panic-handler" } paste = "1.0.15" +pretty_assertions = "1.4.1" proc-macro2 = "1.0.106" quote = "1.0.44" rand = "0.10.0" diff --git a/library/compiler-builtins/ci/run.sh b/library/compiler-builtins/ci/run.sh index e66924b5a9490..130daf92b664e 100755 --- a/library/compiler-builtins/ci/run.sh +++ b/library/compiler-builtins/ci/run.sh @@ -192,7 +192,7 @@ else # Exclude the macros and utile crates from the rest of the tests to save CI # runtime, they shouldn't have anything feature- or opt-level-dependent. - cmd+=(--exclude util --exclude libm-macros) + cmd+=(--exclude util --exclude libm-macros --exclude update-api-list) # Test once with intrinsics enabled "${cmd[@]}" --features arch,unstable-intrinsics diff --git a/library/compiler-builtins/crates/update-api-list/Cargo.toml b/library/compiler-builtins/crates/update-api-list/Cargo.toml new file mode 100644 index 0000000000000..7a14a0e9770f5 --- /dev/null +++ b/library/compiler-builtins/crates/update-api-list/Cargo.toml @@ -0,0 +1,13 @@ +[package] +name = "update-api-list" +version = "0.1.0" +edition = "2024" +publish = false +license = "MIT OR Apache-2.0" + +[dependencies] +api-list-common.workspace = true +getopts.workspace = true +glob.workspace = true +pretty_assertions.workspace = true +regex.workspace = true diff --git a/library/compiler-builtins/crates/update-api-list/src/lib.rs b/library/compiler-builtins/crates/update-api-list/src/lib.rs new file mode 100644 index 0000000000000..a07ae3411ee37 --- /dev/null +++ b/library/compiler-builtins/crates/update-api-list/src/lib.rs @@ -0,0 +1,11 @@ +use std::path::{Path, PathBuf}; +use std::sync::LazyLock; + +pub static WORKSPACE_ROOT: LazyLock = LazyLock::new(|| { + Path::new(env!("CARGO_MANIFEST_DIR")) + .parent() + .unwrap() + .parent() + .unwrap() + .to_owned() +}); diff --git a/library/compiler-builtins/crates/update-api-list/tests/all.rs b/library/compiler-builtins/crates/update-api-list/tests/all.rs new file mode 100644 index 0000000000000..814c7cc3fa0ca --- /dev/null +++ b/library/compiler-builtins/crates/update-api-list/tests/all.rs @@ -0,0 +1,128 @@ +use std::fs; +use std::path::Path; +use std::process::Command; +use std::sync::LazyLock; + +use pretty_assertions::assert_str_eq; +use regex::Regex; +use update_api_list::WORKSPACE_ROOT; + +static PUBLIC_FUNCTIONS: LazyLock> = LazyLock::new(|| { + fs::read_to_string(WORKSPACE_ROOT.join("etc/function-list.txt")) + .unwrap() + .lines() + .map(|line| line.trim()) + .filter(|line| !(line.starts_with("#") || line.is_empty())) + .map(|line| line.to_owned()) + .collect() +}); + +/// In each file, check annotations indicating that blocks of code should be sorted or should +/// include an exhaustive list of all public API. +#[test] +fn tidy_lists() { + let out = Command::new("git") + .arg("ls-files") + .current_dir(&*WORKSPACE_ROOT) + .output() + .unwrap(); + assert!(out.status.success()); + + let file_list = str::from_utf8(&out.stdout).unwrap(); + + for path in file_list.lines() { + let relpath = Path::new(path); + let abspath = WORKSPACE_ROOT.join(relpath); + if abspath.is_dir() || relpath == file!() { + continue; + } + + let src = fs::read_to_string(&abspath).unwrap(); + let lines: Vec<_> = src.lines().collect(); + + validate_delimited_block( + relpath, + &lines, + "verify-sorted-start", + "verify-sorted-end", + ensure_sorted, + ); + + validate_delimited_block( + relpath, + &lines, + "verify-apilist-start", + "verify-apilist-end", + ensure_contains_api, + ); + } +} + +/// Identify blocks of code wrapped within `start` and `end`, collect their contents to a list of +/// strings, and call `validate` for each of those lists. +fn validate_delimited_block( + relpath: &Path, + lines: &[&str], + start: &str, + end: &str, + validate: impl Fn(&Path, usize, &[&str]), +) { + let mut block_lines = Vec::new(); + let mut block_start_line = None; + for (mut line_num, line) in lines.iter().enumerate() { + line_num += 1; + + if line.contains(start) { + block_start_line = Some(line_num); + continue; + } + + // End of a block, validate its contents + if line.contains(end) { + let Some(start_line) = block_start_line else { + panic!("`{end}` without `{start}` at {relpath:?}:{line_num}"); + }; + + validate(relpath, start_line, &block_lines); + block_lines.clear(); + block_start_line = None; + continue; + } + + if block_start_line.is_some() { + block_lines.push(*line); + } + } + + if let Some(start_line) = block_start_line { + panic!("`{start}` without `{end}` at {relpath:?}:{start_line}"); + } +} + +/// Given a list of strings, ensure that each public function we have is named somewhere. +fn ensure_contains_api(relpath: &Path, block_start_line: usize, lines: &[&str]) { + let mut not_found = Vec::new(); + + for func in &*PUBLIC_FUNCTIONS { + // The function name may be on its own or somewhere in a snake case string. + let re = Regex::new(&format!(r"(\b|_){func}(\b|_)")).unwrap(); + if !lines.iter().any(|line| re.is_match(line)) { + not_found.push(func); + } + } + + if not_found.is_empty() { + return; + } + + panic!("functions not found at {relpath:?}:{block_start_line}: {not_found:?}"); +} + +fn ensure_sorted(relpath: &Path, block_start_line: usize, lines: &[&str]) { + let mut sorted = lines.to_owned(); + sorted.sort_unstable(); + let a = lines.join("\n"); + let b = sorted.join("\n"); + + assert_str_eq!(a, b, "sorted block at {relpath:?}:{block_start_line}"); +} diff --git a/library/compiler-builtins/etc/update-api-list.py b/library/compiler-builtins/etc/update-api-list.py index f6fad6466255b..2d8ad2903646d 100755 --- a/library/compiler-builtins/etc/update-api-list.py +++ b/library/compiler-builtins/etc/update-api-list.py @@ -16,7 +16,7 @@ from dataclasses import dataclass from glob import glob from pathlib import Path -from typing import Any, Callable, TypeAlias +from typing import Any, TypeAlias SELF_PATH = Path(__file__) ETC_DIR = SELF_PATH.parent @@ -201,36 +201,6 @@ def write_function_defs(self, check: bool) -> None: with open(out_file, "w") as f: f.write(output) - def tidy_lists(self) -> None: - """In each file, check annotations indicating blocks of code should be sorted or should - include all public API. - """ - - flist = sp.check_output(["git", "ls-files"], cwd=ROOT_DIR, text=True) - - for path in flist.splitlines(): - fpath = ROOT_DIR.joinpath(path) - if fpath.is_dir() or fpath == SELF_PATH: - continue - - lines = fpath.read_text().splitlines() - - validate_delimited_block( - fpath, - lines, - "verify-sorted-start", - "verify-sorted-end", - ensure_sorted, - ) - - validate_delimited_block( - fpath, - lines, - "verify-apilist-start", - "verify-apilist-end", - lambda p, n, lines: self.ensure_contains_api(p, n, lines), - ) - def ensure_contains_api(self, fpath: Path, line_num: int, lines: list[str]): """Given a list of strings, ensure that each public function we have is named somewhere. @@ -252,54 +222,6 @@ def ensure_contains_api(self, fpath: Path, line_num: int, lines: list[str]): exit(1) -def validate_delimited_block( - fpath: Path, - lines: list[str], - start: str, - end: str, - validate: Callable[[Path, int, list[str]], None], -) -> None: - """Identify blocks of code wrapped within `start` and `end`, collect their contents - to a list of strings, and call `validate` for each of those lists. - """ - relpath = fpath.relative_to(ROOT_DIR) - block_lines = [] - block_start_line: None | int = None - for line_num, line in enumerate(lines): - line_num += 1 - - if start in line: - block_start_line = line_num - continue - - if end in line: - if block_start_line is None: - eprint(f"`{end}` without `{start}` at {relpath}:{line_num}") - exit(1) - - validate(fpath, block_start_line, block_lines) - block_lines = [] - block_start_line = None - continue - - if block_start_line is not None: - block_lines.append(line) - - if block_start_line is not None: - eprint(f"`{start}` without `{end}` at {relpath}:{block_start_line}") - exit(1) - - -def ensure_sorted(fpath: Path, block_start_line: int, lines: list[str]) -> None: - """Ensure that a list of lines is sorted, otherwise print a diff and exit.""" - relpath = fpath.relative_to(ROOT_DIR) - diff_and_exit( - "\n".join(lines), - "\n".join(sorted(lines)), - f"sorted block at {relpath}:{block_start_line}", - ) - - def diff_and_exit(actual: str, expected: str, name: str): """If the two strings are different, print a diff between them and then exit with an error. @@ -356,8 +278,6 @@ def ensure_updated_list(check: bool) -> None: crate.write_function_list(check) crate.write_function_defs(check) - crate.tidy_lists() - def main(): """By default overwrite the file. If `--check` is passed, print a diff instead and From fd47f7079057d1fccf208f2c9220fb70921f4efe Mon Sep 17 00:00:00 2001 From: Mend Renovate Date: Tue, 14 Apr 2026 04:40:45 +0000 Subject: [PATCH 117/183] chore(deps): update rust crate rand to v0.10.1 [security] --- library/compiler-builtins/Cargo.lock | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/library/compiler-builtins/Cargo.lock b/library/compiler-builtins/Cargo.lock index 7a3e580f4e6b1..8be7191b0ce89 100644 --- a/library/compiler-builtins/Cargo.lock +++ b/library/compiler-builtins/Cargo.lock @@ -951,9 +951,9 @@ checksum = "f8dcc9c7d52a811697d2151c701e0d08956f92b0e24136cf4cf27b57a6a0d9bf" [[package]] name = "rand" -version = "0.10.0" +version = "0.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bc266eb313df6c5c09c1c7b1fbe2510961e5bcd3add930c1e31f7ed9da0feff8" +checksum = "d2e8e8bcc7961af1fdac401278c6a831614941f6164ee3bf4ce61b7edb162207" dependencies = [ "chacha20", "getrandom", From b2877ac70d2a81045fad8a210f7bf2cbf60aa308 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Thu, 16 Apr 2026 04:03:59 -0400 Subject: [PATCH 118/183] ci: Exclude update-api-list from libm tests --- library/compiler-builtins/ci/run.sh | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/library/compiler-builtins/ci/run.sh b/library/compiler-builtins/ci/run.sh index 130daf92b664e..93c551dc52ec7 100755 --- a/library/compiler-builtins/ci/run.sh +++ b/library/compiler-builtins/ci/run.sh @@ -132,6 +132,9 @@ mflags+=(--no-default-features) # change any implementations. mflags+=(--features unstable-float) +# This is a host program that may not run in containers. +mflags+=(--exclude update-api-list) + # We need to specifically skip tests for musl-math-sys on systems that can't # build musl since otherwise `--all` will activate it. case "$target" in @@ -192,7 +195,7 @@ else # Exclude the macros and utile crates from the rest of the tests to save CI # runtime, they shouldn't have anything feature- or opt-level-dependent. - cmd+=(--exclude util --exclude libm-macros --exclude update-api-list) + cmd+=(--exclude util --exclude libm-macros) # Test once with intrinsics enabled "${cmd[@]}" --features arch,unstable-intrinsics From b61f1716c731c592afadbd84dbfff1c3b50c9445 Mon Sep 17 00:00:00 2001 From: Mend Renovate Date: Thu, 16 Apr 2026 09:55:52 +0000 Subject: [PATCH 119/183] chore(deps): update rust crate gungraun to 0.18.0 --- library/compiler-builtins/Cargo.lock | 12 ++++++------ library/compiler-builtins/Cargo.toml | 2 +- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/library/compiler-builtins/Cargo.lock b/library/compiler-builtins/Cargo.lock index 8be7191b0ce89..45197592cde56 100644 --- a/library/compiler-builtins/Cargo.lock +++ b/library/compiler-builtins/Cargo.lock @@ -508,9 +508,9 @@ dependencies = [ [[package]] name = "gungraun" -version = "0.17.2" +version = "0.18.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "61c1bbe46f51c63bc08a1fac0ee0c530a77c961613a86ecf828ab1b0ffc6687a" +checksum = "2e2e7d17b75a18300d495a5e79970067b92d74e4858c28326e125f2d55b1b566" dependencies = [ "bincode", "derive_more", @@ -520,9 +520,9 @@ dependencies = [ [[package]] name = "gungraun-macros" -version = "0.7.2" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cdccd089c36fb2ee66ef0eb7b1baa3ce7e7878a8eae682d9c8c368869ff6eca1" +checksum = "e35c7fb6133421db1cf752b7a2838d9277a26810ccaeeca7aa449f96ad7c2b01" dependencies = [ "derive_more", "proc-macro-error2", @@ -536,9 +536,9 @@ dependencies = [ [[package]] name = "gungraun-runner" -version = "0.17.2" +version = "0.18.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6da6487203fa53ae6b1c8fead642fe79a3199464b0dd1337635594d675a9ac05" +checksum = "c19bb4c552085f983300b11694022d7584810dca3500c220962ab2353327fb45" dependencies = [ "serde", ] diff --git a/library/compiler-builtins/Cargo.toml b/library/compiler-builtins/Cargo.toml index a925939d53567..6c353aa79c896 100644 --- a/library/compiler-builtins/Cargo.toml +++ b/library/compiler-builtins/Cargo.toml @@ -46,7 +46,7 @@ getopts = "0.2.24" getrandom = "0.4.1" glob = "0.3.3" gmp-mpfr-sys = { version = "1.6.8", default-features = false } -gungraun = "0.17.2" +gungraun = "0.18.0" heck = "0.5.0" indicatif = { version = "0.18.3", default-features = false } libm = { path = "libm", default-features = false } From c7c1c1a8d05eba802b0063391e15d28bce939949 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Thu, 16 Apr 2026 04:06:13 -0400 Subject: [PATCH 120/183] c-b: Better document where `CmpResult` comes from --- .../compiler-builtins/src/float/cmp.rs | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/library/compiler-builtins/compiler-builtins/src/float/cmp.rs b/library/compiler-builtins/compiler-builtins/src/float/cmp.rs index 60247fddb35df..07fe2845f7a7f 100644 --- a/library/compiler-builtins/compiler-builtins/src/float/cmp.rs +++ b/library/compiler-builtins/compiler-builtins/src/float/cmp.rs @@ -2,7 +2,13 @@ use crate::support::{Float, MinInt, cfg_if}; -// Taken from LLVM config [1], which should match GCC's `CMPtype` [2]. +// These definitions should be consistent with LLVM's definition from `getCmpLibcallReturnType`, +// compiler-rt's definitions [1], GCC's `CMPtype` [2], and `libgcc`. To find the definitions +// in GCC, there are a few things to grep for: +// +// * `default_libgcc_cmp_return_mode` for the default (word sized) +// * `TARGET_LIBGCC_CMP_RETURN_MODE` for the target hook to override the default +// * `# *define *CMPtype` as a last resort, for overrides that don't use the hook (AVR) // // [1]: https://github.com/llvm/llvm-project/blob/0cf3c437c18ed27d9663d87804a9a15ff6874af2/compiler-rt/lib/builtins/fp_compare_impl.inc#L11-L27 // [2]: https://gcc.gnu.org/onlinedocs/gccint/Soft-float-library-routines.html#Comparison-functions-1 @@ -14,8 +20,8 @@ cfg_if! { // AVR uses a single byte. pub type CmpResult = i8; } else { - // In compiler-rt, LLP64 ABIs use `long long` and everything else uses `long`. In effect, - // this means the return value is always pointer-sized. + // The default is word-sized. In LLVM's compiler-rt, this is done by using `long long` on + // LLP64 ABIs and `long` on everything else. pub type CmpResult = isize; } } From 32ccc13554389829bbcb6828ae20eaec42ef5e26 Mon Sep 17 00:00:00 2001 From: gamma0987 Date: Fri, 10 Apr 2026 22:49:42 +0200 Subject: [PATCH 121/183] fix: Remove duplicate icount_bench_gef128_group in libm-test benches --- library/compiler-builtins/libm-test/benches/icount.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/library/compiler-builtins/libm-test/benches/icount.rs b/library/compiler-builtins/libm-test/benches/icount.rs index 28a69e747fd3a..70fdb6e45b1c2 100644 --- a/library/compiler-builtins/libm-test/benches/icount.rs +++ b/library/compiler-builtins/libm-test/benches/icount.rs @@ -395,7 +395,6 @@ main!( icount_bench_ftoi_f64_u32_group, icount_bench_ftoi_f64_u64_group, icount_bench_gef128_group, - icount_bench_gef128_group, icount_bench_gef16_group, icount_bench_gef32_group, icount_bench_gef64_group, From dcb70deadfe168b33d0130094e7cd920b52a9160 Mon Sep 17 00:00:00 2001 From: Spxg Date: Thu, 16 Apr 2026 21:31:38 +0800 Subject: [PATCH 122/183] Fix the type of `CmpResult` on wasm64 resolve rust-lang/compiler-builtins#1199 --- library/compiler-builtins/compiler-builtins/src/float/cmp.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/library/compiler-builtins/compiler-builtins/src/float/cmp.rs b/library/compiler-builtins/compiler-builtins/src/float/cmp.rs index 07fe2845f7a7f..a59365a2bdb8b 100644 --- a/library/compiler-builtins/compiler-builtins/src/float/cmp.rs +++ b/library/compiler-builtins/compiler-builtins/src/float/cmp.rs @@ -13,8 +13,9 @@ use crate::support::{Float, MinInt, cfg_if}; // [1]: https://github.com/llvm/llvm-project/blob/0cf3c437c18ed27d9663d87804a9a15ff6874af2/compiler-rt/lib/builtins/fp_compare_impl.inc#L11-L27 // [2]: https://gcc.gnu.org/onlinedocs/gccint/Soft-float-library-routines.html#Comparison-functions-1 cfg_if! { - if #[cfg(any(target_arch = "aarch64", target_arch = "arm64ec"))] { + if #[cfg(any(target_arch = "aarch64", target_arch = "arm64ec", target_family = "wasm"))] { // Aarch64 uses `int` rather than a pointer-sized value. + // `getCmpLibcallReturnType` for WASM is always set to i32. pub type CmpResult = i32; } else if #[cfg(target_arch = "avr")] { // AVR uses a single byte. From 5d4b1764c1a2e08eb006e1d25f17a3eff15cdcfb Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Fri, 10 Apr 2026 18:11:39 -0400 Subject: [PATCH 123/183] bench: Use a group with many benches rather than many groups --- .../libm-test/benches/icount.rs | 636 +++++++++--------- 1 file changed, 319 insertions(+), 317 deletions(-) diff --git a/library/compiler-builtins/libm-test/benches/icount.rs b/library/compiler-builtins/libm-test/benches/icount.rs index 70fdb6e45b1c2..f67f7b049d30e 100644 --- a/library/compiler-builtins/libm-test/benches/icount.rs +++ b/library/compiler-builtins/libm-test/benches/icount.rs @@ -41,11 +41,6 @@ macro_rules! icount_benches { input.call(f); } } - - library_benchmark_group!( - name = [< icount_bench_ $fn_name _group >]; - benchmarks = [< icount_bench_ $fn_name >] - ); } }; } @@ -54,6 +49,324 @@ libm_macros::for_each_function! { callback: icount_benches, } +library_benchmark_group!( + name = icount_bench_math_group, + benchmarks = [ + // verify-apilist-start + // verify-sorted-start + icount_bench_acos, + icount_bench_acosf, + icount_bench_acosh, + icount_bench_acoshf, + icount_bench_addf128, + icount_bench_addf16, + icount_bench_addf32, + icount_bench_addf64, + icount_bench_ashl_u128, + icount_bench_ashl_u32, + icount_bench_ashl_u64, + icount_bench_ashr_i128, + icount_bench_ashr_i32, + icount_bench_ashr_i64, + icount_bench_asin, + icount_bench_asinf, + icount_bench_asinh, + icount_bench_asinhf, + icount_bench_atan, + icount_bench_atan2, + icount_bench_atan2f, + icount_bench_atanf, + icount_bench_atanh, + icount_bench_atanhf, + icount_bench_cbrt, + icount_bench_cbrtf, + icount_bench_ceil, + icount_bench_ceilf, + icount_bench_ceilf128, + icount_bench_ceilf16, + icount_bench_copysign, + icount_bench_copysignf, + icount_bench_copysignf128, + icount_bench_copysignf16, + icount_bench_cos, + icount_bench_cosf, + icount_bench_cosh, + icount_bench_coshf, + icount_bench_divf128, + icount_bench_divf32, + icount_bench_divf64, + icount_bench_eqf128, + icount_bench_eqf16, + icount_bench_eqf32, + icount_bench_eqf64, + icount_bench_erf, + icount_bench_erfc, + icount_bench_erfcf, + icount_bench_erff, + icount_bench_exp, + icount_bench_exp10, + icount_bench_exp10f, + icount_bench_exp2, + icount_bench_exp2f, + icount_bench_expf, + icount_bench_expm1, + icount_bench_expm1f, + icount_bench_extend_f16_f128, + icount_bench_extend_f16_f32, + icount_bench_extend_f16_f64, + icount_bench_extend_f32_f128, + icount_bench_extend_f32_f64, + icount_bench_extend_f64_f128, + icount_bench_fabs, + icount_bench_fabsf, + icount_bench_fabsf128, + icount_bench_fabsf16, + icount_bench_fdim, + icount_bench_fdimf, + icount_bench_fdimf128, + icount_bench_fdimf16, + icount_bench_floor, + icount_bench_floorf, + icount_bench_floorf128, + icount_bench_floorf16, + icount_bench_fma, + icount_bench_fmaf, + icount_bench_fmaf128, + icount_bench_fmax, + icount_bench_fmaxf, + icount_bench_fmaxf128, + icount_bench_fmaxf16, + icount_bench_fmaximum, + icount_bench_fmaximum_num, + icount_bench_fmaximum_numf, + icount_bench_fmaximum_numf128, + icount_bench_fmaximum_numf16, + icount_bench_fmaximumf, + icount_bench_fmaximumf128, + icount_bench_fmaximumf16, + icount_bench_fmin, + icount_bench_fminf, + icount_bench_fminf128, + icount_bench_fminf16, + icount_bench_fminimum, + icount_bench_fminimum_num, + icount_bench_fminimum_numf, + icount_bench_fminimum_numf128, + icount_bench_fminimum_numf16, + icount_bench_fminimumf, + icount_bench_fminimumf128, + icount_bench_fminimumf16, + icount_bench_fmod, + icount_bench_fmodf, + icount_bench_fmodf128, + icount_bench_fmodf16, + icount_bench_frexp, + icount_bench_frexpf, + icount_bench_frexpf128, + icount_bench_frexpf16, + icount_bench_ftoi_f128_i128, + icount_bench_ftoi_f128_i32, + icount_bench_ftoi_f128_i64, + icount_bench_ftoi_f128_u128, + icount_bench_ftoi_f128_u32, + icount_bench_ftoi_f128_u64, + icount_bench_ftoi_f32_i128, + icount_bench_ftoi_f32_i32, + icount_bench_ftoi_f32_i64, + icount_bench_ftoi_f32_u128, + icount_bench_ftoi_f32_u32, + icount_bench_ftoi_f32_u64, + icount_bench_ftoi_f64_i128, + icount_bench_ftoi_f64_i32, + icount_bench_ftoi_f64_i64, + icount_bench_ftoi_f64_u128, + icount_bench_ftoi_f64_u32, + icount_bench_ftoi_f64_u64, + icount_bench_gef128, + icount_bench_gef16, + icount_bench_gef32, + icount_bench_gef64, + icount_bench_gtf128, + icount_bench_gtf16, + icount_bench_gtf32, + icount_bench_gtf64, + icount_bench_hypot, + icount_bench_hypotf, + icount_bench_iadd_i128, + icount_bench_iadd_u128, + icount_bench_iaddo_i128, + icount_bench_iaddo_u128, + icount_bench_idiv_i128, + icount_bench_idiv_i32, + icount_bench_idiv_i64, + icount_bench_idiv_u128, + icount_bench_idiv_u32, + icount_bench_idiv_u64, + icount_bench_idivmod_i128, + icount_bench_idivmod_i32, + icount_bench_idivmod_i64, + icount_bench_idivmod_u128, + icount_bench_idivmod_u32, + icount_bench_idivmod_u64, + icount_bench_ilogb, + icount_bench_ilogbf, + icount_bench_ilogbf128, + icount_bench_ilogbf16, + icount_bench_imod_i128, + icount_bench_imod_i32, + icount_bench_imod_i64, + icount_bench_imod_u128, + icount_bench_imod_u32, + icount_bench_imod_u64, + icount_bench_imul_i128, + icount_bench_imul_u64, + icount_bench_imulo_i128, + icount_bench_imulo_i32, + icount_bench_imulo_i64, + icount_bench_imulo_u128, + icount_bench_isub_i128, + icount_bench_isub_u128, + icount_bench_isubo_i128, + icount_bench_isubo_u128, + icount_bench_itof_i128_f128, + icount_bench_itof_i128_f32, + icount_bench_itof_i128_f64, + icount_bench_itof_i32_f128, + icount_bench_itof_i32_f32, + icount_bench_itof_i32_f64, + icount_bench_itof_i64_f128, + icount_bench_itof_i64_f32, + icount_bench_itof_i64_f64, + icount_bench_itof_u128_f128, + icount_bench_itof_u128_f32, + icount_bench_itof_u128_f64, + icount_bench_itof_u32_f128, + icount_bench_itof_u32_f32, + icount_bench_itof_u32_f64, + icount_bench_itof_u64_f128, + icount_bench_itof_u64_f32, + icount_bench_itof_u64_f64, + icount_bench_j0, + icount_bench_j0f, + icount_bench_j1, + icount_bench_j1f, + icount_bench_jn, + icount_bench_jnf, + icount_bench_ldexp, + icount_bench_ldexpf, + icount_bench_ldexpf128, + icount_bench_ldexpf16, + icount_bench_leading_zeros_u128, + icount_bench_leading_zeros_u32, + icount_bench_leading_zeros_u64, + icount_bench_lef128, + icount_bench_lef16, + icount_bench_lef32, + icount_bench_lef64, + icount_bench_lgamma, + icount_bench_lgamma_r, + icount_bench_lgammaf, + icount_bench_lgammaf_r, + icount_bench_log, + icount_bench_log10, + icount_bench_log10f, + icount_bench_log1p, + icount_bench_log1pf, + icount_bench_log2, + icount_bench_log2f, + icount_bench_logf, + icount_bench_lshr_u128, + icount_bench_lshr_u32, + icount_bench_lshr_u64, + icount_bench_ltf128, + icount_bench_ltf16, + icount_bench_ltf32, + icount_bench_ltf64, + icount_bench_modf, + icount_bench_modff, + icount_bench_mulf128, + icount_bench_mulf16, + icount_bench_mulf32, + icount_bench_mulf64, + icount_bench_narrow_f128_f16, + icount_bench_narrow_f128_f32, + icount_bench_narrow_f128_f64, + icount_bench_narrow_f32_f16, + icount_bench_narrow_f64_f16, + icount_bench_narrow_f64_f32, + icount_bench_nef128, + icount_bench_nef16, + icount_bench_nef32, + icount_bench_nef64, + icount_bench_nextafter, + icount_bench_nextafterf, + icount_bench_pow, + icount_bench_powf, + icount_bench_powif128, + icount_bench_powif32, + icount_bench_powif64, + icount_bench_remainder, + icount_bench_remainderf, + icount_bench_remquo, + icount_bench_remquof, + icount_bench_rint, + icount_bench_rintf, + icount_bench_rintf128, + icount_bench_rintf16, + icount_bench_round, + icount_bench_roundeven, + icount_bench_roundevenf, + icount_bench_roundevenf128, + icount_bench_roundevenf16, + icount_bench_roundf, + icount_bench_roundf128, + icount_bench_roundf16, + icount_bench_scalbn, + icount_bench_scalbnf, + icount_bench_scalbnf128, + icount_bench_scalbnf16, + icount_bench_sin, + icount_bench_sincos, + icount_bench_sincosf, + icount_bench_sinf, + icount_bench_sinh, + icount_bench_sinhf, + icount_bench_sqrt, + icount_bench_sqrtf, + icount_bench_sqrtf128, + icount_bench_sqrtf16, + icount_bench_subf128, + icount_bench_subf16, + icount_bench_subf32, + icount_bench_subf64, + icount_bench_tan, + icount_bench_tanf, + icount_bench_tanh, + icount_bench_tanhf, + icount_bench_tgamma, + icount_bench_tgammaf, + icount_bench_trailing_zeros_u128, + icount_bench_trailing_zeros_u32, + icount_bench_trailing_zeros_u64, + icount_bench_trunc, + icount_bench_truncf, + icount_bench_truncf128, + icount_bench_truncf16, + icount_bench_unordf128, + icount_bench_unordf16, + icount_bench_unordf32, + icount_bench_unordf64, + icount_bench_y0, + icount_bench_y0f, + icount_bench_y1, + icount_bench_y1f, + icount_bench_yn, + icount_bench_ynf, + // verify-sorted-end + // verify-apilist-end + ] +); + fn setup_u128_mul() -> Vec<(u128, u128)> { let step = u128::MAX / 300; let mut x = 0u128; @@ -264,317 +577,6 @@ main!( icount_bench_u128_group, icount_bench_hf_parse_group, icount_bench_hf_print_group, - // verify-apilist-start - // verify-sorted-start - icount_bench_acos_group, - icount_bench_acosf_group, - icount_bench_acosh_group, - icount_bench_acoshf_group, - icount_bench_addf128_group, - icount_bench_addf16_group, - icount_bench_addf32_group, - icount_bench_addf64_group, - icount_bench_ashl_u128_group, - icount_bench_ashl_u32_group, - icount_bench_ashl_u64_group, - icount_bench_ashr_i128_group, - icount_bench_ashr_i32_group, - icount_bench_ashr_i64_group, - icount_bench_asin_group, - icount_bench_asinf_group, - icount_bench_asinh_group, - icount_bench_asinhf_group, - icount_bench_atan2_group, - icount_bench_atan2f_group, - icount_bench_atan_group, - icount_bench_atanf_group, - icount_bench_atanh_group, - icount_bench_atanhf_group, - icount_bench_cbrt_group, - icount_bench_cbrtf_group, - icount_bench_ceil_group, - icount_bench_ceilf128_group, - icount_bench_ceilf16_group, - icount_bench_ceilf_group, - icount_bench_copysign_group, - icount_bench_copysignf128_group, - icount_bench_copysignf16_group, - icount_bench_copysignf_group, - icount_bench_cos_group, - icount_bench_cosf_group, - icount_bench_cosh_group, - icount_bench_coshf_group, - icount_bench_divf128_group, - icount_bench_divf32_group, - icount_bench_divf64_group, - icount_bench_eqf128_group, - icount_bench_eqf16_group, - icount_bench_eqf32_group, - icount_bench_eqf64_group, - icount_bench_erf_group, - icount_bench_erfc_group, - icount_bench_erfcf_group, - icount_bench_erff_group, - icount_bench_exp10_group, - icount_bench_exp10f_group, - icount_bench_exp2_group, - icount_bench_exp2f_group, - icount_bench_exp_group, - icount_bench_expf_group, - icount_bench_expm1_group, - icount_bench_expm1f_group, - icount_bench_extend_f16_f128_group, - icount_bench_extend_f16_f32_group, - icount_bench_extend_f16_f64_group, - icount_bench_extend_f32_f128_group, - icount_bench_extend_f32_f64_group, - icount_bench_extend_f64_f128_group, - icount_bench_fabs_group, - icount_bench_fabsf128_group, - icount_bench_fabsf16_group, - icount_bench_fabsf_group, - icount_bench_fdim_group, - icount_bench_fdimf128_group, - icount_bench_fdimf16_group, - icount_bench_fdimf_group, - icount_bench_floor_group, - icount_bench_floorf128_group, - icount_bench_floorf16_group, - icount_bench_floorf_group, - icount_bench_fma_group, - icount_bench_fmaf128_group, - icount_bench_fmaf_group, - icount_bench_fmax_group, - icount_bench_fmaxf128_group, - icount_bench_fmaxf16_group, - icount_bench_fmaxf_group, - icount_bench_fmaximum_group, - icount_bench_fmaximum_num_group, - icount_bench_fmaximum_numf128_group, - icount_bench_fmaximum_numf16_group, - icount_bench_fmaximum_numf_group, - icount_bench_fmaximumf128_group, - icount_bench_fmaximumf16_group, - icount_bench_fmaximumf_group, - icount_bench_fmin_group, - icount_bench_fminf128_group, - icount_bench_fminf16_group, - icount_bench_fminf_group, - icount_bench_fminimum_group, - icount_bench_fminimum_num_group, - icount_bench_fminimum_numf128_group, - icount_bench_fminimum_numf16_group, - icount_bench_fminimum_numf_group, - icount_bench_fminimumf128_group, - icount_bench_fminimumf16_group, - icount_bench_fminimumf_group, - icount_bench_fmod_group, - icount_bench_fmodf128_group, - icount_bench_fmodf16_group, - icount_bench_fmodf_group, - icount_bench_frexp_group, - icount_bench_frexpf128_group, - icount_bench_frexpf16_group, - icount_bench_frexpf_group, - icount_bench_ftoi_f128_i128_group, - icount_bench_ftoi_f128_i32_group, - icount_bench_ftoi_f128_i64_group, - icount_bench_ftoi_f128_u128_group, - icount_bench_ftoi_f128_u32_group, - icount_bench_ftoi_f128_u64_group, - icount_bench_ftoi_f32_i128_group, - icount_bench_ftoi_f32_i32_group, - icount_bench_ftoi_f32_i64_group, - icount_bench_ftoi_f32_u128_group, - icount_bench_ftoi_f32_u32_group, - icount_bench_ftoi_f32_u64_group, - icount_bench_ftoi_f64_i128_group, - icount_bench_ftoi_f64_i32_group, - icount_bench_ftoi_f64_i64_group, - icount_bench_ftoi_f64_u128_group, - icount_bench_ftoi_f64_u32_group, - icount_bench_ftoi_f64_u64_group, - icount_bench_gef128_group, - icount_bench_gef16_group, - icount_bench_gef32_group, - icount_bench_gef64_group, - icount_bench_gtf128_group, - icount_bench_gtf16_group, - icount_bench_gtf32_group, - icount_bench_gtf64_group, - icount_bench_hypot_group, - icount_bench_hypotf_group, - icount_bench_iadd_i128_group, - icount_bench_iadd_u128_group, - icount_bench_iaddo_i128_group, - icount_bench_iaddo_u128_group, - icount_bench_idiv_i128_group, - icount_bench_idiv_i32_group, - icount_bench_idiv_i64_group, - icount_bench_idiv_u128_group, - icount_bench_idiv_u32_group, - icount_bench_idiv_u64_group, - icount_bench_idivmod_i128_group, - icount_bench_idivmod_i32_group, - icount_bench_idivmod_i64_group, - icount_bench_idivmod_u128_group, - icount_bench_idivmod_u32_group, - icount_bench_idivmod_u64_group, - icount_bench_ilogb_group, - icount_bench_ilogbf128_group, - icount_bench_ilogbf16_group, - icount_bench_ilogbf_group, - icount_bench_imod_i128_group, - icount_bench_imod_i32_group, - icount_bench_imod_i64_group, - icount_bench_imod_u128_group, - icount_bench_imod_u32_group, - icount_bench_imod_u64_group, - icount_bench_imul_i128_group, - icount_bench_imul_u64_group, - icount_bench_imulo_i128_group, - icount_bench_imulo_i32_group, - icount_bench_imulo_i64_group, - icount_bench_imulo_u128_group, - icount_bench_isub_i128_group, - icount_bench_isub_u128_group, - icount_bench_isubo_i128_group, - icount_bench_isubo_u128_group, - icount_bench_itof_i128_f128_group, - icount_bench_itof_i128_f32_group, - icount_bench_itof_i128_f64_group, - icount_bench_itof_i32_f128_group, - icount_bench_itof_i32_f32_group, - icount_bench_itof_i32_f64_group, - icount_bench_itof_i64_f128_group, - icount_bench_itof_i64_f32_group, - icount_bench_itof_i64_f64_group, - icount_bench_itof_u128_f128_group, - icount_bench_itof_u128_f32_group, - icount_bench_itof_u128_f64_group, - icount_bench_itof_u32_f128_group, - icount_bench_itof_u32_f32_group, - icount_bench_itof_u32_f64_group, - icount_bench_itof_u64_f128_group, - icount_bench_itof_u64_f32_group, - icount_bench_itof_u64_f64_group, - icount_bench_j0_group, - icount_bench_j0f_group, - icount_bench_j1_group, - icount_bench_j1f_group, - icount_bench_jn_group, - icount_bench_jnf_group, - icount_bench_ldexp_group, - icount_bench_ldexpf128_group, - icount_bench_ldexpf16_group, - icount_bench_ldexpf_group, - icount_bench_leading_zeros_u128_group, - icount_bench_leading_zeros_u32_group, - icount_bench_leading_zeros_u64_group, - icount_bench_lef128_group, - icount_bench_lef16_group, - icount_bench_lef32_group, - icount_bench_lef64_group, - icount_bench_lgamma_group, - icount_bench_lgamma_r_group, - icount_bench_lgammaf_group, - icount_bench_lgammaf_r_group, - icount_bench_log10_group, - icount_bench_log10f_group, - icount_bench_log1p_group, - icount_bench_log1pf_group, - icount_bench_log2_group, - icount_bench_log2f_group, - icount_bench_log_group, - icount_bench_logf_group, - icount_bench_lshr_u128_group, - icount_bench_lshr_u32_group, - icount_bench_lshr_u64_group, - icount_bench_ltf128_group, - icount_bench_ltf16_group, - icount_bench_ltf32_group, - icount_bench_ltf64_group, - icount_bench_modf_group, - icount_bench_modff_group, - icount_bench_mulf128_group, - icount_bench_mulf16_group, - icount_bench_mulf32_group, - icount_bench_mulf64_group, - icount_bench_narrow_f128_f16_group, - icount_bench_narrow_f128_f32_group, - icount_bench_narrow_f128_f64_group, - icount_bench_narrow_f32_f16_group, - icount_bench_narrow_f64_f16_group, - icount_bench_narrow_f64_f32_group, - icount_bench_nef128_group, - icount_bench_nef16_group, - icount_bench_nef32_group, - icount_bench_nef64_group, - icount_bench_nextafter_group, - icount_bench_nextafterf_group, - icount_bench_pow_group, - icount_bench_powf_group, - icount_bench_powif128_group, - icount_bench_powif32_group, - icount_bench_powif64_group, - icount_bench_remainder_group, - icount_bench_remainderf_group, - icount_bench_remquo_group, - icount_bench_remquof_group, - icount_bench_rint_group, - icount_bench_rintf128_group, - icount_bench_rintf16_group, - icount_bench_rintf_group, - icount_bench_round_group, - icount_bench_roundeven_group, - icount_bench_roundevenf128_group, - icount_bench_roundevenf16_group, - icount_bench_roundevenf_group, - icount_bench_roundf128_group, - icount_bench_roundf16_group, - icount_bench_roundf_group, - icount_bench_scalbn_group, - icount_bench_scalbnf128_group, - icount_bench_scalbnf16_group, - icount_bench_scalbnf_group, - icount_bench_sin_group, - icount_bench_sincos_group, - icount_bench_sincosf_group, - icount_bench_sinf_group, - icount_bench_sinh_group, - icount_bench_sinhf_group, - icount_bench_sqrt_group, - icount_bench_sqrtf128_group, - icount_bench_sqrtf16_group, - icount_bench_sqrtf_group, - icount_bench_subf128_group, - icount_bench_subf16_group, - icount_bench_subf32_group, - icount_bench_subf64_group, - icount_bench_tan_group, - icount_bench_tanf_group, - icount_bench_tanh_group, - icount_bench_tanhf_group, - icount_bench_tgamma_group, - icount_bench_tgammaf_group, - icount_bench_trailing_zeros_u128_group, - icount_bench_trailing_zeros_u32_group, - icount_bench_trailing_zeros_u64_group, - icount_bench_trunc_group, - icount_bench_truncf128_group, - icount_bench_truncf16_group, - icount_bench_truncf_group, - icount_bench_unordf128_group, - icount_bench_unordf16_group, - icount_bench_unordf32_group, - icount_bench_unordf64_group, - icount_bench_y0_group, - icount_bench_y0f_group, - icount_bench_y1_group, - icount_bench_y1f_group, - icount_bench_yn_group, - icount_bench_ynf_group, - // verify-sorted-end - // verify-apilist-end + icount_bench_math_group, ] ); From 9064d17405e21924fd87cd187ce64a7fbf17c63f Mon Sep 17 00:00:00 2001 From: nataliakokoromyti Date: Sat, 18 Apr 2026 10:51:16 -0700 Subject: [PATCH 124/183] Do not suggest borrowing enclosing calls for nested where-clause obligations --- .../src/error_reporting/traits/ambiguity.rs | 1 + .../traits/fulfillment_errors.rs | 17 ++++++++ .../src/error_reporting/traits/suggestions.rs | 42 +++++++++++++++++++ ...-suggest-borrow-whole-call-issue-155088.rs | 8 ++++ ...gest-borrow-whole-call-issue-155088.stderr | 15 +++++++ 5 files changed, 83 insertions(+) create mode 100644 tests/ui/suggestions/dont-suggest-borrow-whole-call-issue-155088.rs create mode 100644 tests/ui/suggestions/dont-suggest-borrow-whole-call-issue-155088.stderr diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/ambiguity.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/ambiguity.rs index 7f5ed9ecb6d11..cff842d9d316f 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/traits/ambiguity.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/traits/ambiguity.rs @@ -349,6 +349,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { if impl_candidates.len() < 40 { self.report_similar_impl_candidates( impl_candidates.as_slice(), + obligation, trait_pred, obligation.cause.body_id, &mut err, diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs index 43ab4a64fbedc..7a02cdadc735b 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs @@ -2008,6 +2008,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { pub(super) fn report_similar_impl_candidates( &self, impl_candidates: &[ImplCandidate<'tcx>], + obligation: &PredicateObligation<'tcx>, trait_pred: ty::PolyTraitPredicate<'tcx>, body_def_id: LocalDefId, err: &mut Diag<'_>, @@ -2072,6 +2073,20 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { }; if let [single] = &impl_candidates { + let self_ty = trait_pred.skip_binder().self_ty(); + if !self_ty.has_escaping_bound_vars() { + let self_ty = self.tcx.instantiate_bound_regions_with_erased(trait_pred.self_ty()); + if let ty::Ref(_, inner_ty, _) = self_ty.kind() + && self.can_eq(param_env, single.trait_ref.self_ty(), *inner_ty) + && !self.where_clause_expr_matches_failed_self_ty(obligation, self_ty) + { + // Avoid pointing at a nearby impl like `String: Borrow` when the + // failing obligation comes from something nested inside an enclosing call + // expression such as `foo(&[String::from("a")])`. + return true; + } + } + // If we have a single implementation, try to unify it with the trait ref // that failed. This should uncover a better hint for what *is* implemented. if self.probe(|_| { @@ -2491,6 +2506,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { let impl_candidates = self.find_similar_impl_candidates(trait_pred); self.report_similar_impl_candidates( &impl_candidates, + obligation, trait_pred, body_def_id, err, @@ -3165,6 +3181,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { let impl_candidates = self.find_similar_impl_candidates(trait_predicate); if !self.report_similar_impl_candidates( &impl_candidates, + obligation, trait_predicate, body_def_id, err, diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs index 62f6b87c9e98c..6946c17f62e53 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs @@ -1467,6 +1467,39 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { if output.is_ty_var() { None } else { Some((def_id_or_name, output, inputs)) } } + pub(super) fn where_clause_expr_matches_failed_self_ty( + &self, + obligation: &PredicateObligation<'tcx>, + old_self_ty: Ty<'tcx>, + ) -> bool { + let ObligationCauseCode::WhereClauseInExpr(..) = obligation.cause.code() else { + return true; + }; + let (Some(typeck_results), Some(body)) = ( + self.typeck_results.as_ref(), + self.tcx.hir_maybe_body_owned_by(obligation.cause.body_id), + ) else { + return true; + }; + + let mut expr_finder = FindExprBySpan::new(obligation.cause.span, self.tcx); + expr_finder.visit_expr(body.value); + let Some(expr) = expr_finder.result else { + return true; + }; + + let inner_old_self_ty = match old_self_ty.kind() { + ty::Ref(_, inner_ty, _) => Some(*inner_ty), + _ => None, + }; + + [typeck_results.expr_ty_adjusted_opt(expr)].into_iter().flatten().any(|expr_ty| { + self.can_eq(obligation.param_env, expr_ty, old_self_ty) + || inner_old_self_ty + .is_some_and(|inner_ty| self.can_eq(obligation.param_env, expr_ty, inner_ty)) + }) + } + pub(super) fn suggest_add_reference_to_arg( &self, obligation: &PredicateObligation<'tcx>, @@ -1740,6 +1773,15 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { if let hir::ExprKind::AddrOf(_, _, _) = expr.kind { return false; } + let old_self_ty = old_pred.skip_binder().self_ty(); + if !old_self_ty.has_escaping_bound_vars() + && !self.where_clause_expr_matches_failed_self_ty( + obligation, + self.tcx.instantiate_bound_regions_with_erased(old_pred.self_ty()), + ) + { + return false; + } let needs_parens_post = expr_needs_parens(expr); let needs_parens_pre = match self.tcx.parent_hir_node(expr.hir_id) { Node::Expr(e) diff --git a/tests/ui/suggestions/dont-suggest-borrow-whole-call-issue-155088.rs b/tests/ui/suggestions/dont-suggest-borrow-whole-call-issue-155088.rs new file mode 100644 index 0000000000000..d8e2e7091d6e0 --- /dev/null +++ b/tests/ui/suggestions/dont-suggest-borrow-whole-call-issue-155088.rs @@ -0,0 +1,8 @@ +use std::borrow::Borrow; + +fn foo(_v: impl IntoIterator>) {} + +fn main() { + foo(&[String::from("a")]); + //~^ ERROR the trait bound `&String: Borrow` is not satisfied +} diff --git a/tests/ui/suggestions/dont-suggest-borrow-whole-call-issue-155088.stderr b/tests/ui/suggestions/dont-suggest-borrow-whole-call-issue-155088.stderr new file mode 100644 index 0000000000000..8910ed892ec03 --- /dev/null +++ b/tests/ui/suggestions/dont-suggest-borrow-whole-call-issue-155088.stderr @@ -0,0 +1,15 @@ +error[E0277]: the trait bound `&String: Borrow` is not satisfied + --> $DIR/dont-suggest-borrow-whole-call-issue-155088.rs:6:5 + | +LL | foo(&[String::from("a")]); + | ^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Borrow` is not implemented for `&String` + | +note: required by a bound in `foo` + --> $DIR/dont-suggest-borrow-whole-call-issue-155088.rs:3:42 + | +LL | fn foo(_v: impl IntoIterator>) {} + | ^^^^^^^^^^^ required by this bound in `foo` + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0277`. From 0cc3a7d6fe332f11dc51690dacc565b1a25d5c5f Mon Sep 17 00:00:00 2001 From: Daniel Scherzer Date: Fri, 17 Apr 2026 16:10:25 -0700 Subject: [PATCH 125/183] c-b: add missing word in src/mem/impls.rs docs --- library/compiler-builtins/compiler-builtins/src/mem/impls.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/compiler-builtins/src/mem/impls.rs b/library/compiler-builtins/compiler-builtins/src/mem/impls.rs index a6486381bf75c..c7cfa6fb4618e 100644 --- a/library/compiler-builtins/compiler-builtins/src/mem/impls.rs +++ b/library/compiler-builtins/compiler-builtins/src/mem/impls.rs @@ -9,7 +9,7 @@ // ptr::add in these loops will wrap. And if compiler-builtins is compiled with cfg(ub_checks), // this will fail a UB check at runtime. // -// Since this scenario is UB, we are within our rights hit this check and halt execution... +// Since this scenario is UB, we are within our rights to hit this check and halt execution... // But we are also within our rights to try to make it work. // We use wrapping_add/wrapping_sub for pointer arithmetic in this module in an attempt to support // this use. Of course this is not a guarantee that such use will work, it just means that this From 996b57d5bc9d5747a49e1ce087e60775d70bd928 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Sun, 19 Apr 2026 02:41:56 +0000 Subject: [PATCH 126/183] test: Fix printing bitwise float reprs in error printing In commit "test: Consolidate `Hexf`, `Hexi`, and the `Hex` trait" we unintentionally lost the difference between float hex and bitwise hex formatting; instead, the float hex was getting printed twice. Resolve this by printing the integer hex whenever the `-` format modifier is specified. This also makes things simpler because we no longer need to keep track of whether an `impl DisplayHex` is a float with `.to_bits()` available or an integer without it, we can always just try to print both forms. As a result, we can use a common error message for all validation checks. --- .../libm-test/src/test_traits.rs | 97 ++++++++++--------- .../libm/src/math/support/hex_float.rs | 27 +++++- 2 files changed, 74 insertions(+), 50 deletions(-) diff --git a/library/compiler-builtins/libm-test/src/test_traits.rs b/library/compiler-builtins/libm-test/src/test_traits.rs index ab91715c71243..a1b48224bfd47 100644 --- a/library/compiler-builtins/libm-test/src/test_traits.rs +++ b/library/compiler-builtins/libm-test/src/test_traits.rs @@ -232,19 +232,15 @@ where None => String::new(), }; - anyhow::ensure!( - result, - "\ - \n input: {input:?} {ibits}\ - \n expected: {expected:<22?} {expbits}\ - \n actual: {actual:<22?} {actbits}\ - \n {msg}\ - ", - actbits = Hex(actual), - expbits = Hex(expected), - ibits = Hex(input), - msg = make_xfail_msg() - ); + if !result { + bail!(make_error_message( + input, + expected, + actual, + "", + &make_xfail_msg() + )); + } Ok(()) } @@ -360,23 +356,7 @@ where } } - res.with_context(|| { - format!( - "\ - \n input: {input:?}\ - \n as hex: {ihex}\ - \n as bits: {ibits}\ - \n expected: {expected:<22?} {exphex} {expbits}\ - \n actual: {actual:<22?} {acthex} {actbits}\ - ", - ihex = Hex(input), - ibits = Hex(input), - exphex = Hex(expected), - expbits = Hex(expected), - actbits = Hex(actual), - acthex = Hex(actual), - ) - }) + res.with_context(|| make_error_message(input, expected, actual, "", "")) } impl_float!(f32, f64); @@ -397,28 +377,25 @@ macro_rules! impl_tuples { where Input: Copy + DisplayHex + fmt::Debug, SpecialCase: MaybeOverride, - { + { fn validate<'a>( self, expected: Self, input: Input, ctx: &CheckCtx, ) -> TestResult { - self.0.validate(expected.0, input, ctx) + self.0 + .validate(expected.0, input, ctx) .and_then(|()| self.1.validate(expected.1, input, ctx)) - .with_context(|| format!( - "full context:\ - \n input: {input:?} {ibits}\ - \n as hex: {ihex}\ - \n as bits: {ibits}\ - \n expected: {expected:?} {expbits}\ - \n actual: {self:?} {actbits}\ - ", - ihex = Hex(input), - ibits = Hex(input), - expbits = Hex(expected), - actbits = Hex(self), - )) + .with_context(|| { + make_error_message( + input, + expected, + self, + "full context:", + "", + ) + }) } } )* @@ -459,3 +436,33 @@ impl_tuples!( (f128, i32); (f128, f128); ); + +fn make_error_message( + input: I, + expected: E, + actual: A, + pre_msg: &str, + post_msg: &str, +) -> String +where + I: Copy + fmt::Debug + DisplayHex, + E: Copy + fmt::Debug + DisplayHex, + A: Copy + fmt::Debug + DisplayHex, +{ + let pre_pad = if pre_msg.is_empty() { "" } else { "\n " }; + let post_pad = if post_msg.is_empty() { "" } else { "\n " }; + format!( + "\ + {pre_pad}{pre_msg}\ + \n input: {input:?}\ + \n as hex: {ihex}\ + \n as bits: {ihex:-}\ + \n expected: {expected:<16?} {exphex} {exphex:-}\ + \n actual: {actual:<16?} {acthex} {acthex:-}\ + {post_pad}{post_msg}\ + ", + ihex = Hex(input), + exphex = Hex(expected), + acthex = Hex(actual), + ) +} diff --git a/library/compiler-builtins/libm/src/math/support/hex_float.rs b/library/compiler-builtins/libm/src/math/support/hex_float.rs index 933b2f640afef..e1100a4a119f0 100644 --- a/library/compiler-builtins/libm/src/math/support/hex_float.rs +++ b/library/compiler-builtins/libm/src/math/support/hex_float.rs @@ -378,7 +378,8 @@ mod hex_fmt { } /// Types that can be formatted as hex via `Hex`. For ints we always print with a fixed - /// number of leading zeros. For floats we use the IEEE hex (`%a`) representation. + /// number of leading zeros. For floats we use the IEEE hex (`%a`) representation. The `-` + /// format modifier is used to print the integer hex representation rather than hex float. pub trait DisplayHex { #[allow(unused)] // Only used for tests and public test internals fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result; @@ -408,7 +409,11 @@ mod hex_fmt { impl DisplayHex for F { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - fmt_any_hex(self, f) + if f.sign_minus() { + self.to_bits().fmt(f) + } else { + fmt_any_hex(self, f) + } } } @@ -459,7 +464,9 @@ mod hex_fmt { T1: Copy + DisplayHex, { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "({},)", Hex(self.0)) + write!(f, "(")?; + self.0.fmt(f)?; + write!(f, ",)") } } @@ -469,7 +476,11 @@ mod hex_fmt { T2: Copy + DisplayHex, { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "({}, {})", Hex(self.0), Hex(self.1)) + write!(f, "(")?; + self.0.fmt(f)?; + write!(f, ", ")?; + self.1.fmt(f)?; + write!(f, ")") } } @@ -480,7 +491,13 @@ mod hex_fmt { T3: Copy + DisplayHex, { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "({}, {}, {})", Hex(self.0), Hex(self.1), Hex(self.2)) + write!(f, "(")?; + self.0.fmt(f)?; + write!(f, ", ")?; + self.1.fmt(f)?; + write!(f, ", ")?; + self.2.fmt(f)?; + write!(f, ")") } } } From aa38b7fcacbc5443a3bc6b205cd9ef50feabc932 Mon Sep 17 00:00:00 2001 From: Folkert de Vries Date: Wed, 8 Oct 2025 15:29:24 +0200 Subject: [PATCH 127/183] add `MaybeUninit` to `minicore` --- tests/auxiliary/minicore.rs | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/tests/auxiliary/minicore.rs b/tests/auxiliary/minicore.rs index 24da2c4a1c4e8..4830253e89d45 100644 --- a/tests/auxiliary/minicore.rs +++ b/tests/auxiliary/minicore.rs @@ -27,6 +27,7 @@ decl_macro, f16, f128, + transparent_unions, asm_experimental_arch, unboxed_closures )] @@ -127,6 +128,25 @@ pub struct ManuallyDrop { } impl Copy for ManuallyDrop {} +#[lang = "maybe_uninit"] +#[repr(transparent)] +pub union MaybeUninit { + uninit: (), + value: ManuallyDrop, +} + +impl Copy for MaybeUninit {} + +impl MaybeUninit { + pub const fn uninit() -> Self { + Self { uninit: () } + } + + pub const fn new(value: T) -> Self { + Self { value: ManuallyDrop { value } } + } +} + #[repr(transparent)] #[rustc_nonnull_optimization_guaranteed] pub struct NonNull { From 640c4b4f1e96fe37675493ccd8ab2e3c2229fd39 Mon Sep 17 00:00:00 2001 From: Folkert de Vries Date: Sun, 19 Apr 2026 18:30:12 +0200 Subject: [PATCH 128/183] cmse: test returning `MaybeUninit` The `MaybeUninit` type is `repr(transparent)`, so returning a `MaybeUninit` should work. The same is not true when using C or rust union types. --- .../cmse-nonsecure-call/return-via-stack.rs | 14 +++++++---- .../cmse-nonsecure-entry/params-via-stack.rs | 23 +++++++++++++++++++ 2 files changed, 33 insertions(+), 4 deletions(-) diff --git a/tests/ui/cmse-nonsecure/cmse-nonsecure-call/return-via-stack.rs b/tests/ui/cmse-nonsecure/cmse-nonsecure-call/return-via-stack.rs index 55160f7a0f003..a8c69216e2048 100644 --- a/tests/ui/cmse-nonsecure/cmse-nonsecure-call/return-via-stack.rs +++ b/tests/ui/cmse-nonsecure/cmse-nonsecure-call/return-via-stack.rs @@ -42,13 +42,13 @@ struct Test { i128: extern "cmse-nonsecure-call" fn() -> i128, //~ ERROR [E0798] } -#[repr(C)] -pub union ReprCUnionU64 { +#[repr(Rust)] +pub union ReprRustUnionU64 { _unused: u64, } -#[repr(Rust)] -pub union ReprRustUnionU64 { +#[repr(C)] +pub union ReprCUnionU64 { _unused: u64, } @@ -56,5 +56,11 @@ pub union ReprRustUnionU64 { pub fn test_union( f1: extern "cmse-nonsecure-call" fn() -> ReprRustUnionU64, //~ ERROR [E0798] f2: extern "cmse-nonsecure-call" fn() -> ReprCUnionU64, //~ ERROR [E0798] + + // MaybeUninit is a transparent union, and hence MaybeUninit is abi-compatible with u64, + // and thus allowed as a return type. + f3: extern "cmse-nonsecure-call" fn() -> MaybeUninit, + f4: extern "cmse-nonsecure-call" fn() -> MaybeUninit, + f5: extern "cmse-nonsecure-call" fn() -> MaybeUninit, ) { } diff --git a/tests/ui/cmse-nonsecure/cmse-nonsecure-entry/params-via-stack.rs b/tests/ui/cmse-nonsecure/cmse-nonsecure-entry/params-via-stack.rs index 2e73ef8c32f5b..b46e73abad0e8 100644 --- a/tests/ui/cmse-nonsecure/cmse-nonsecure-entry/params-via-stack.rs +++ b/tests/ui/cmse-nonsecure/cmse-nonsecure-entry/params-via-stack.rs @@ -45,3 +45,26 @@ pub extern "cmse-nonsecure-entry" fn four(_: Four) {} #[no_mangle] pub extern "cmse-nonsecure-entry" fn five(_: Five) {} //~ ERROR [E0798] + +#[repr(Rust)] +pub union ReprRustUnionU64 { + _unused: u64, +} + +#[repr(C)] +pub union ReprCUnionU64 { + _unused: u64, +} + +#[no_mangle] +#[allow(improper_ctypes_definitions)] +pub extern "cmse-nonsecure-entry" fn union_rust(_: ReprRustUnionU64) {} + +#[no_mangle] +pub extern "cmse-nonsecure-entry" fn union_c(_: ReprCUnionU64) {} + +#[no_mangle] +pub extern "cmse-nonsecure-entry" fn maybe_uninit_32bit(_: MaybeUninit) {} + +#[no_mangle] +pub extern "cmse-nonsecure-entry" fn maybe_uninit_64bit(_: MaybeUninit) {} From 90a0227843d1142b8d800ff86fb94db7fb0c7bf7 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Mon, 20 Apr 2026 10:15:12 +0000 Subject: [PATCH 129/183] support: Update vendored cfg-if to upstream for `true` and `false` support Link: https://github.com/rust-lang/cfg-if/commit/15aec4a67e633254e726bf477b8b86c65687bfc6 --- .../libm/src/math/support/macros.rs | 77 ++++++++++++------- 1 file changed, 51 insertions(+), 26 deletions(-) diff --git a/library/compiler-builtins/libm/src/math/support/macros.rs b/library/compiler-builtins/libm/src/math/support/macros.rs index fa4167d656686..f1bfa21eec7f7 100644 --- a/library/compiler-builtins/libm/src/math/support/macros.rs +++ b/library/compiler-builtins/libm/src/math/support/macros.rs @@ -1,42 +1,67 @@ /// `libm` cannot have dependencies, so this is vendored directly from the `cfg-if` crate /// (with some comments stripped for compactness). macro_rules! cfg_if { - // match if/else chains with a final `else` - ($( - if #[cfg($meta:meta)] { $($tokens:tt)* } - ) else * else { - $($tokens2:tt)* - }) => { - cfg_if! { @__items () ; $( ( ($meta) ($($tokens)*) ), )* ( () ($($tokens2)*) ), } - }; - - // match if/else chains lacking a final `else` ( - if #[cfg($i_met:meta)] { $($i_tokens:tt)* } - $( else if #[cfg($e_met:meta)] { $($e_tokens:tt)* } )* + if #[cfg( $($i_meta:tt)+ )] { $( $i_tokens:tt )* } + $( + else if #[cfg( $($ei_meta:tt)+ )] { $( $ei_tokens:tt )* } + )* + $( + else { $( $e_tokens:tt )* } + )? ) => { cfg_if! { - @__items - () ; - ( ($i_met) ($($i_tokens)*) ), - $( ( ($e_met) ($($e_tokens)*) ), )* - ( () () ), + @__items () ; + (( $($i_meta)+ ) ( $( $i_tokens )* )), + $( + (( $($ei_meta)+ ) ( $( $ei_tokens )* )), + )* + $( + (() ( $( $e_tokens )* )), + )? } }; // Internal and recursive macro to emit all the items // - // Collects all the negated cfgs in a list at the beginning and after the - // semicolon is all the remaining items - (@__items ($($not:meta,)*) ; ) => {}; - (@__items ($($not:meta,)*) ; ( ($($m:meta),*) ($($tokens:tt)*) ), $($rest:tt)*) => { - #[cfg(all($($m,)* not(any($($not),*))))] cfg_if! { @__identity $($tokens)* } - cfg_if! { @__items ($($not,)* $($m,)*) ; $($rest)* } + // Collects all the previous cfgs in a list at the beginning, so they can be + // negated. After the semicolon are all the remaining items. + (@__items ( $( ($($_:tt)*) , )* ) ; ) => {}; + ( + @__items ( $( ($($no:tt)+) , )* ) ; + (( $( $($yes:tt)+ )? ) ( $( $tokens:tt )* )), + $( $rest:tt , )* + ) => { + // Emit all items within one block, applying an appropriate #[cfg]. The + // #[cfg] will require all `$yes` matchers specified and must also negate + // all previous matchers. + #[cfg(all( + $( $($yes)+ , )? + not(any( $( $($no)+ ),* )) + ))] + // Subtle: You might think we could put `$( $tokens )*` here. But if + // that contains multiple items then the `#[cfg(all(..))]` above would + // only apply to the first one. By wrapping `$( $tokens )*` in this + // macro call, we temporarily group the items into a single thing (the + // macro call) that will be included/excluded by the `#[cfg(all(..))]` + // as appropriate. If the `#[cfg(all(..))]` succeeds, the macro call + // will be included, and then evaluated, producing `$( $tokens )*`. See + // also the "issue #90" test below. + cfg_if! { @__temp_group $( $tokens )* } + + // Recurse to emit all other items in `$rest`, and when we do so add all + // our `$yes` matchers to the list of `$no` matchers as future emissions + // will have to negate everything we just matched as well. + cfg_if! { + @__items ( $( ($($no)+) , )* $( ($($yes)+) , )? ) ; + $( $rest , )* + } }; - // Internal macro to make __apply work out right for different match types, - // because of how macros matching/expand stuff. - (@__identity $($tokens:tt)*) => { $($tokens)* }; + // See the "Subtle" comment above. + (@__temp_group $( $tokens:tt )* ) => { + $( $tokens )* + }; } /// Choose between using an arch-specific implementation and the function body. Returns directly From e981edde2b2f3d6eb56818aa7ee6b44f273d5ef7 Mon Sep 17 00:00:00 2001 From: Chris Burel Date: Mon, 20 Apr 2026 17:29:22 -0400 Subject: [PATCH 130/183] Enable AddressSanitizer on arm-unknown-linux-gnueabihf and armv7-unknown-linux-gnueabihf Add SanitizerSet::ADDRESS to the supported_sanitizers for the arm-unknown-linux-gnueabihf and armv7-unknown-linux-gnueabihf targets. The AddressSanitizer is already enabled on the armv7-linux-androideabi platform, which shares the same ARM architecture. There is no reason these Linux GNU targets should not also support it, as the underlying LLVM support for ASan on 32-bit ARM is already in place. --- .../src/spec/targets/arm_unknown_linux_gnueabihf.rs | 5 ++++- .../src/spec/targets/armv7_unknown_linux_gnueabihf.rs | 5 ++++- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/compiler/rustc_target/src/spec/targets/arm_unknown_linux_gnueabihf.rs b/compiler/rustc_target/src/spec/targets/arm_unknown_linux_gnueabihf.rs index 7dd36d6e82c45..1e4f70ebcd310 100644 --- a/compiler/rustc_target/src/spec/targets/arm_unknown_linux_gnueabihf.rs +++ b/compiler/rustc_target/src/spec/targets/arm_unknown_linux_gnueabihf.rs @@ -1,4 +1,6 @@ -use crate::spec::{Arch, CfgAbi, FloatAbi, Target, TargetMetadata, TargetOptions, base}; +use crate::spec::{ + Arch, CfgAbi, FloatAbi, SanitizerSet, Target, TargetMetadata, TargetOptions, base, +}; pub(crate) fn target() -> Target { Target { @@ -24,6 +26,7 @@ pub(crate) fn target() -> Target { // linker error, so set it to `true` here. // FIXME(#146996): Remove this override once #146996 has been fixed. default_uwtable: false, + supported_sanitizers: SanitizerSet::ADDRESS, ..base::linux_gnu::opts() }, } diff --git a/compiler/rustc_target/src/spec/targets/armv7_unknown_linux_gnueabihf.rs b/compiler/rustc_target/src/spec/targets/armv7_unknown_linux_gnueabihf.rs index a1f90b307c3ce..8bf3dfd247229 100644 --- a/compiler/rustc_target/src/spec/targets/armv7_unknown_linux_gnueabihf.rs +++ b/compiler/rustc_target/src/spec/targets/armv7_unknown_linux_gnueabihf.rs @@ -1,4 +1,6 @@ -use crate::spec::{Arch, CfgAbi, FloatAbi, Target, TargetMetadata, TargetOptions, base}; +use crate::spec::{ + Arch, CfgAbi, FloatAbi, SanitizerSet, Target, TargetMetadata, TargetOptions, base, +}; // This target is for glibc Linux on ARMv7 without NEON or // thumb-mode. See the thumbv7neon variant for enabling both. @@ -23,6 +25,7 @@ pub(crate) fn target() -> Target { max_atomic_width: Some(64), mcount: "\u{1}__gnu_mcount_nc".into(), llvm_mcount_intrinsic: Some("llvm.arm.gnu.eabi.mcount".into()), + supported_sanitizers: SanitizerSet::ADDRESS, ..base::linux_gnu::opts() }, } From 70cf3f4fda39193c8d78979144b7aaeafae3e97d Mon Sep 17 00:00:00 2001 From: mejrs <59372212+mejrs@users.noreply.github.com> Date: Tue, 21 Apr 2026 23:42:33 +0200 Subject: [PATCH 131/183] Put `#[diagnostic::on_move]` on `File` --- library/std/src/fs.rs | 1 + library/std/src/lib.rs | 1 + .../diagnostic_namespace/on_move/std_impls.rs | 25 ++++++++++ .../on_move/std_impls.stderr | 49 +++++++++++++++++++ 4 files changed, 76 insertions(+) create mode 100644 tests/ui/diagnostic_namespace/on_move/std_impls.rs create mode 100644 tests/ui/diagnostic_namespace/on_move/std_impls.stderr diff --git a/library/std/src/fs.rs b/library/std/src/fs.rs index c75f005f18021..5192343ea4300 100644 --- a/library/std/src/fs.rs +++ b/library/std/src/fs.rs @@ -132,6 +132,7 @@ use crate::{error, fmt}; /// [`read`]: File::read #[stable(feature = "rust1", since = "1.0.0")] #[cfg_attr(not(test), rustc_diagnostic_item = "File")] +#[diagnostic::on_move(note = "you can use `File::try_clone` to duplicate a `File` instance")] pub struct File { inner: fs_imp::File, } diff --git a/library/std/src/lib.rs b/library/std/src/lib.rs index faac8d9e51fd2..976577156c5bd 100644 --- a/library/std/src/lib.rs +++ b/library/std/src/lib.rs @@ -278,6 +278,7 @@ #![feature(const_trait_impl)] #![feature(decl_macro)] #![feature(deprecated_suggestion)] +#![feature(diagnostic_on_move)] #![feature(doc_cfg)] #![feature(doc_masked)] #![feature(doc_notable_trait)] diff --git a/tests/ui/diagnostic_namespace/on_move/std_impls.rs b/tests/ui/diagnostic_namespace/on_move/std_impls.rs new file mode 100644 index 0000000000000..ea63d731a3434 --- /dev/null +++ b/tests/ui/diagnostic_namespace/on_move/std_impls.rs @@ -0,0 +1,25 @@ +//@ dont-require-annotations: NOTE + +use std::fs::File; +use std::sync::Arc; +use std::rc::Rc; + +fn main(){ + let file = File::open("foo.txt").unwrap(); + (file, file); + //~^ ERROR use of moved value: `file` + //~| NOTE you can use `File::try_clone` to duplicate a `File` instance + + let arc = Arc::new(42); + //~^ NOTE this move could be avoided by cloning the original `Arc`, which is inexpensive + (arc, arc); + //~^ ERROR the type `Arc` does not implement `Copy` + //~| NOTE consider using `Arc::clone` + + + let rc = Rc::new(12); + //~^ NOTE this move could be avoided by cloning the original `Rc`, which is inexpensive + (rc, rc); + //~^ ERROR the type `Rc` does not implement `Copy` + //~| NOTE consider using `Rc::clone` +} diff --git a/tests/ui/diagnostic_namespace/on_move/std_impls.stderr b/tests/ui/diagnostic_namespace/on_move/std_impls.stderr new file mode 100644 index 0000000000000..ba8869d9c73fb --- /dev/null +++ b/tests/ui/diagnostic_namespace/on_move/std_impls.stderr @@ -0,0 +1,49 @@ +error[E0382]: use of moved value: `file` + --> $DIR/std_impls.rs:9:12 + | +LL | let file = File::open("foo.txt").unwrap(); + | ---- move occurs because `file` has type `File`, which does not implement the `Copy` trait +LL | (file, file); + | ---- ^^^^ value used here after move + | | + | value moved here + | + = note: you can use `File::try_clone` to duplicate a `File` instance + +error[E0382]: the type `Arc` does not implement `Copy` + --> $DIR/std_impls.rs:15:11 + | +LL | let arc = Arc::new(42); + | --- this move could be avoided by cloning the original `Arc`, which is inexpensive +LL | +LL | (arc, arc); + | --- ^^^ value used here after move + | | + | value moved here + | + = note: consider using `Arc::clone` +help: clone the value to increment its reference count + | +LL | (arc.clone(), arc); + | ++++++++ + +error[E0382]: the type `Rc` does not implement `Copy` + --> $DIR/std_impls.rs:22:10 + | +LL | let rc = Rc::new(12); + | -- this move could be avoided by cloning the original `Rc`, which is inexpensive +LL | +LL | (rc, rc); + | -- ^^ value used here after move + | | + | value moved here + | + = note: consider using `Rc::clone` +help: clone the value to increment its reference count + | +LL | (rc.clone(), rc); + | ++++++++ + +error: aborting due to 3 previous errors + +For more information about this error, try `rustc --explain E0382`. From 05485026ad6f1bfa9669cc8094e6ed872d51c35a Mon Sep 17 00:00:00 2001 From: Daniel Scherzer Date: Fri, 6 Mar 2026 02:07:26 -0800 Subject: [PATCH 132/183] tests/ui/macros: add annotations for reference rules --- tests/ui/macros/expr_2021.rs | 1 + .../expr_2021_inline_const.edi2021.stderr | 8 +- .../expr_2021_inline_const.edi2024.stderr | 4 +- tests/ui/macros/expr_2021_inline_const.rs | 1 + .../expr_2024_underscore_expr.edi2021.stderr | 8 +- .../expr_2024_underscore_expr.edi2024.stderr | 4 +- tests/ui/macros/expr_2024_underscore_expr.rs | 1 + ...ocal-ambiguity-multiple-parsing-options.rs | 1 + ...-ambiguity-multiple-parsing-options.stderr | 4 +- tests/ui/macros/macro-error.rs | 1 + tests/ui/macros/macro-error.stderr | 4 +- tests/ui/macros/macro-follow-rpass.rs | 5 + tests/ui/macros/macro-follow.rs | 4 +- tests/ui/macros/macro-follow.stderr | 178 +++++++++--------- tests/ui/macros/macro-followed-by-seq-bad.rs | 1 + .../macros/macro-followed-by-seq-bad.stderr | 4 +- tests/ui/macros/macro-followed-by-seq.rs | 1 + .../macros/macro-hygiene-help-issue-148580.rs | 1 + .../macro-hygiene-help-issue-148580.stderr | 4 +- .../macros/macro-hygiene-help-issue-149604.rs | 1 + .../macro-hygiene-help-issue-149604.stderr | 8 +- tests/ui/macros/macro-hygiene-scope-15167.rs | 1 + .../macros/macro-hygiene-scope-15167.stderr | 16 +- .../macro-or-patterns-back-compat.fixed | 1 + .../macros/macro-or-patterns-back-compat.rs | 1 + .../macro-or-patterns-back-compat.stderr | 10 +- tests/ui/macros/macro-pat-follow-2018.rs | 1 + tests/ui/macros/macro-pat-follow.rs | 1 + ...acro-pat-pattern-followed-by-or-in-2021.rs | 1 + ...-pat-pattern-followed-by-or-in-2021.stderr | 6 +- .../macro-pat-pattern-followed-by-or.rs | 2 + .../macro-pat2021-pattern-followed-by-or.rs | 2 + ...acro-pat2021-pattern-followed-by-or.stderr | 6 +- ...ro-rules-as-derive-or-attr-issue-132928.rs | 1 + ...ules-as-derive-or-attr-issue-132928.stderr | 6 +- tests/ui/macros/macro-shadowing.rs | 2 + tests/ui/macros/macro-shadowing.stderr | 8 +- tests/ui/macros/macro-use-all-and-none.rs | 1 + tests/ui/macros/macro-use-all-and-none.stderr | 4 +- tests/ui/macros/macro-use-bad-args-1.rs | 1 + tests/ui/macros/macro-use-bad-args-1.stderr | 2 +- tests/ui/macros/macro-use-bad-args-2.rs | 1 + tests/ui/macros/macro-use-bad-args-2.stderr | 2 +- tests/ui/macros/macro-use-both.rs | 2 + tests/ui/macros/module-macro_use-arguments.rs | 1 + .../macros/module-macro_use-arguments.stderr | 2 +- 46 files changed, 180 insertions(+), 145 deletions(-) diff --git a/tests/ui/macros/expr_2021.rs b/tests/ui/macros/expr_2021.rs index 8a274e7753359..7ddeedc7a0b55 100644 --- a/tests/ui/macros/expr_2021.rs +++ b/tests/ui/macros/expr_2021.rs @@ -1,5 +1,6 @@ //@ check-pass //@ edition: 2015 +//@ reference: macro.decl.meta.edition2024 // Ensures expr_2021 fragment specifier is accepted in old editions diff --git a/tests/ui/macros/expr_2021_inline_const.edi2021.stderr b/tests/ui/macros/expr_2021_inline_const.edi2021.stderr index bf7eb3888b33e..997f1d1d73fd3 100644 --- a/tests/ui/macros/expr_2021_inline_const.edi2021.stderr +++ b/tests/ui/macros/expr_2021_inline_const.edi2021.stderr @@ -1,5 +1,5 @@ error: no rules expected keyword `const` - --> $DIR/expr_2021_inline_const.rs:23:12 + --> $DIR/expr_2021_inline_const.rs:24:12 | LL | macro_rules! m2021 { | ------------------ when calling this macro @@ -8,13 +8,13 @@ LL | m2021!(const { 1 }); | ^^^^^ no rules expected this token in macro call | note: while trying to match meta-variable `$e:expr_2021` - --> $DIR/expr_2021_inline_const.rs:7:6 + --> $DIR/expr_2021_inline_const.rs:8:6 | LL | ($e:expr_2021) => { | ^^^^^^^^^^^^ error: no rules expected keyword `const` - --> $DIR/expr_2021_inline_const.rs:24:12 + --> $DIR/expr_2021_inline_const.rs:25:12 | LL | macro_rules! m2024 { | ------------------ when calling this macro @@ -23,7 +23,7 @@ LL | m2024!(const { 1 }); | ^^^^^ no rules expected this token in macro call | note: while trying to match meta-variable `$e:expr` - --> $DIR/expr_2021_inline_const.rs:13:6 + --> $DIR/expr_2021_inline_const.rs:14:6 | LL | ($e:expr) => { | ^^^^^^^ diff --git a/tests/ui/macros/expr_2021_inline_const.edi2024.stderr b/tests/ui/macros/expr_2021_inline_const.edi2024.stderr index 1028ddc4267fc..659738c0bb992 100644 --- a/tests/ui/macros/expr_2021_inline_const.edi2024.stderr +++ b/tests/ui/macros/expr_2021_inline_const.edi2024.stderr @@ -1,5 +1,5 @@ error: no rules expected keyword `const` - --> $DIR/expr_2021_inline_const.rs:23:12 + --> $DIR/expr_2021_inline_const.rs:24:12 | LL | macro_rules! m2021 { | ------------------ when calling this macro @@ -8,7 +8,7 @@ LL | m2021!(const { 1 }); | ^^^^^ no rules expected this token in macro call | note: while trying to match meta-variable `$e:expr_2021` - --> $DIR/expr_2021_inline_const.rs:7:6 + --> $DIR/expr_2021_inline_const.rs:8:6 | LL | ($e:expr_2021) => { | ^^^^^^^^^^^^ diff --git a/tests/ui/macros/expr_2021_inline_const.rs b/tests/ui/macros/expr_2021_inline_const.rs index 257f5b2f8cf98..d660db12328cb 100644 --- a/tests/ui/macros/expr_2021_inline_const.rs +++ b/tests/ui/macros/expr_2021_inline_const.rs @@ -1,6 +1,7 @@ //@ revisions: edi2021 edi2024 //@[edi2024] edition: 2024 //@[edi2021] edition: 2021 +//@ reference: macro.decl.meta.edition2024 // This test ensures that the inline const match only on edition 2024 macro_rules! m2021 { diff --git a/tests/ui/macros/expr_2024_underscore_expr.edi2021.stderr b/tests/ui/macros/expr_2024_underscore_expr.edi2021.stderr index 7b3ca54bb7132..37be53aafc5b0 100644 --- a/tests/ui/macros/expr_2024_underscore_expr.edi2021.stderr +++ b/tests/ui/macros/expr_2024_underscore_expr.edi2021.stderr @@ -1,5 +1,5 @@ error: no rules expected reserved identifier `_` - --> $DIR/expr_2024_underscore_expr.rs:19:12 + --> $DIR/expr_2024_underscore_expr.rs:20:12 | LL | macro_rules! m2021 { | ------------------ when calling this macro @@ -8,13 +8,13 @@ LL | m2021!(_); | ^ no rules expected this token in macro call | note: while trying to match meta-variable `$e:expr_2021` - --> $DIR/expr_2024_underscore_expr.rs:7:6 + --> $DIR/expr_2024_underscore_expr.rs:8:6 | LL | ($e:expr_2021) => { | ^^^^^^^^^^^^ error: no rules expected reserved identifier `_` - --> $DIR/expr_2024_underscore_expr.rs:20:12 + --> $DIR/expr_2024_underscore_expr.rs:21:12 | LL | macro_rules! m2024 { | ------------------ when calling this macro @@ -23,7 +23,7 @@ LL | m2024!(_); | ^ no rules expected this token in macro call | note: while trying to match meta-variable `$e:expr` - --> $DIR/expr_2024_underscore_expr.rs:13:6 + --> $DIR/expr_2024_underscore_expr.rs:14:6 | LL | ($e:expr) => { | ^^^^^^^ diff --git a/tests/ui/macros/expr_2024_underscore_expr.edi2024.stderr b/tests/ui/macros/expr_2024_underscore_expr.edi2024.stderr index 59104dafa1816..831cbd09de9d0 100644 --- a/tests/ui/macros/expr_2024_underscore_expr.edi2024.stderr +++ b/tests/ui/macros/expr_2024_underscore_expr.edi2024.stderr @@ -1,5 +1,5 @@ error: no rules expected reserved identifier `_` - --> $DIR/expr_2024_underscore_expr.rs:19:12 + --> $DIR/expr_2024_underscore_expr.rs:20:12 | LL | macro_rules! m2021 { | ------------------ when calling this macro @@ -8,7 +8,7 @@ LL | m2021!(_); | ^ no rules expected this token in macro call | note: while trying to match meta-variable `$e:expr_2021` - --> $DIR/expr_2024_underscore_expr.rs:7:6 + --> $DIR/expr_2024_underscore_expr.rs:8:6 | LL | ($e:expr_2021) => { | ^^^^^^^^^^^^ diff --git a/tests/ui/macros/expr_2024_underscore_expr.rs b/tests/ui/macros/expr_2024_underscore_expr.rs index 1d45d60c13644..e216dbb191e18 100644 --- a/tests/ui/macros/expr_2024_underscore_expr.rs +++ b/tests/ui/macros/expr_2024_underscore_expr.rs @@ -1,6 +1,7 @@ //@ revisions: edi2021 edi2024 //@[edi2024] edition: 2024 //@[edi2021] edition: 2021 +//@ reference: macro.decl.meta.edition2024 // This test ensures that the `_` tok is considered an // expression on edition 2024. macro_rules! m2021 { diff --git a/tests/ui/macros/local-ambiguity-multiple-parsing-options.rs b/tests/ui/macros/local-ambiguity-multiple-parsing-options.rs index 3967481098cff..d15850d43a288 100644 --- a/tests/ui/macros/local-ambiguity-multiple-parsing-options.rs +++ b/tests/ui/macros/local-ambiguity-multiple-parsing-options.rs @@ -1,3 +1,4 @@ +//@ reference: macro.decl.transcription.lookahead fn main() {} macro_rules! ambiguity { diff --git a/tests/ui/macros/local-ambiguity-multiple-parsing-options.stderr b/tests/ui/macros/local-ambiguity-multiple-parsing-options.stderr index 68b278fd3c886..80fc66f7e36b6 100644 --- a/tests/ui/macros/local-ambiguity-multiple-parsing-options.stderr +++ b/tests/ui/macros/local-ambiguity-multiple-parsing-options.stderr @@ -1,11 +1,11 @@ error: local ambiguity when calling macro `ambiguity`: multiple parsing options: built-in NTs ident ('i') or ident ('j'). - --> $DIR/local-ambiguity-multiple-parsing-options.rs:7:12 + --> $DIR/local-ambiguity-multiple-parsing-options.rs:8:12 | LL | ambiguity!(error); | ^^^^^ error: local ambiguity when calling macro `ambiguity`: multiple parsing options: built-in NTs ident ('i') or ident ('j'). - --> $DIR/local-ambiguity-multiple-parsing-options.rs:8:12 + --> $DIR/local-ambiguity-multiple-parsing-options.rs:9:12 | LL | ambiguity!(error); | ^^^^^ diff --git a/tests/ui/macros/macro-error.rs b/tests/ui/macros/macro-error.rs index 4984b92911efc..20ae8c137a569 100644 --- a/tests/ui/macros/macro-error.rs +++ b/tests/ui/macros/macro-error.rs @@ -1,3 +1,4 @@ +//@ reference: macro.decl.syntax macro_rules! foo { ($a:expr) => a; //~ ERROR macro rhs must be delimited } diff --git a/tests/ui/macros/macro-error.stderr b/tests/ui/macros/macro-error.stderr index fcf8d922d65c9..f3bab7af9b640 100644 --- a/tests/ui/macros/macro-error.stderr +++ b/tests/ui/macros/macro-error.stderr @@ -1,11 +1,11 @@ error: macro rhs must be delimited - --> $DIR/macro-error.rs:2:18 + --> $DIR/macro-error.rs:3:18 | LL | ($a:expr) => a; | ^ error: non-type macro in type position: cfg - --> $DIR/macro-error.rs:8:12 + --> $DIR/macro-error.rs:9:12 | LL | let _: cfg!(FALSE) = (); | ^^^^^^^^^^^ diff --git a/tests/ui/macros/macro-follow-rpass.rs b/tests/ui/macros/macro-follow-rpass.rs index 3103e86539a65..b407f10249890 100644 --- a/tests/ui/macros/macro-follow-rpass.rs +++ b/tests/ui/macros/macro-follow-rpass.rs @@ -1,5 +1,10 @@ //@ edition:2015..2021 //@ check-pass +//@ reference: macro.decl.follow-set.token-expr-stmt +//@ reference: macro.decl.follow-set.token-pat +//@ reference: macro.decl.follow-set.edition2021 +//@ reference: macro.decl.follow-set.token-path-ty +//@ reference: macro.decl.follow-set.token-other #![allow(unused_macros)] // Check the macro follow sets (see corresponding cfail test). diff --git a/tests/ui/macros/macro-follow.rs b/tests/ui/macros/macro-follow.rs index 874bad6a74316..cf83a9ad734bd 100644 --- a/tests/ui/macros/macro-follow.rs +++ b/tests/ui/macros/macro-follow.rs @@ -1,5 +1,7 @@ //@ edition:2015..2021 -// +//@ reference: macro.decl.follow-set.token-expr-stmt +//@ reference: macro.decl.follow-set.token-pat +//@ reference: macro.decl.follow-set.token-path-ty // Check the macro follow sets (see corresponding rpass test). #![feature(macro_guard_matcher)] diff --git a/tests/ui/macros/macro-follow.stderr b/tests/ui/macros/macro-follow.stderr index 78d167added73..64a916b4c227a 100644 --- a/tests/ui/macros/macro-follow.stderr +++ b/tests/ui/macros/macro-follow.stderr @@ -1,5 +1,5 @@ error: `$p:pat` is followed by `(`, which is not allowed for `pat` fragments - --> $DIR/macro-follow.rs:10:13 + --> $DIR/macro-follow.rs:12:13 | LL | ($p:pat ()) => {}; | ^ not allowed after `pat` fragments @@ -7,7 +7,7 @@ LL | ($p:pat ()) => {}; = note: allowed there are: `=>`, `,`, `=`, `|`, `if`, `if let` or `in` error: `$p:pat` is followed by `[`, which is not allowed for `pat` fragments - --> $DIR/macro-follow.rs:11:13 + --> $DIR/macro-follow.rs:13:13 | LL | ($p:pat []) => {}; | ^ not allowed after `pat` fragments @@ -15,7 +15,7 @@ LL | ($p:pat []) => {}; = note: allowed there are: `=>`, `,`, `=`, `|`, `if`, `if let` or `in` error: `$p:pat` is followed by `{`, which is not allowed for `pat` fragments - --> $DIR/macro-follow.rs:12:13 + --> $DIR/macro-follow.rs:14:13 | LL | ($p:pat {}) => {}; | ^ not allowed after `pat` fragments @@ -23,7 +23,7 @@ LL | ($p:pat {}) => {}; = note: allowed there are: `=>`, `,`, `=`, `|`, `if`, `if let` or `in` error: `$p:pat` is followed by `:`, which is not allowed for `pat` fragments - --> $DIR/macro-follow.rs:13:13 + --> $DIR/macro-follow.rs:15:13 | LL | ($p:pat :) => {}; | ^ not allowed after `pat` fragments @@ -31,7 +31,7 @@ LL | ($p:pat :) => {}; = note: allowed there are: `=>`, `,`, `=`, `|`, `if`, `if let` or `in` error: `$p:pat` is followed by `>`, which is not allowed for `pat` fragments - --> $DIR/macro-follow.rs:14:13 + --> $DIR/macro-follow.rs:16:13 | LL | ($p:pat >) => {}; | ^ not allowed after `pat` fragments @@ -39,7 +39,7 @@ LL | ($p:pat >) => {}; = note: allowed there are: `=>`, `,`, `=`, `|`, `if`, `if let` or `in` error: `$p:pat` is followed by `+`, which is not allowed for `pat` fragments - --> $DIR/macro-follow.rs:15:13 + --> $DIR/macro-follow.rs:17:13 | LL | ($p:pat +) => {}; | ^ not allowed after `pat` fragments @@ -47,7 +47,7 @@ LL | ($p:pat +) => {}; = note: allowed there are: `=>`, `,`, `=`, `|`, `if`, `if let` or `in` error: `$p:pat` is followed by `ident`, which is not allowed for `pat` fragments - --> $DIR/macro-follow.rs:16:13 + --> $DIR/macro-follow.rs:18:13 | LL | ($p:pat ident) => {}; | ^^^^^ not allowed after `pat` fragments @@ -55,7 +55,7 @@ LL | ($p:pat ident) => {}; = note: allowed there are: `=>`, `,`, `=`, `|`, `if`, `if let` or `in` error: `$p:pat` is followed by `$q:pat`, which is not allowed for `pat` fragments - --> $DIR/macro-follow.rs:17:13 + --> $DIR/macro-follow.rs:19:13 | LL | ($p:pat $q:pat) => {}; | ^^^^^^ not allowed after `pat` fragments @@ -63,7 +63,7 @@ LL | ($p:pat $q:pat) => {}; = note: allowed there are: `=>`, `,`, `=`, `|`, `if`, `if let` or `in` error: `$p:pat` is followed by `$e:expr`, which is not allowed for `pat` fragments - --> $DIR/macro-follow.rs:18:13 + --> $DIR/macro-follow.rs:20:13 | LL | ($p:pat $e:expr) => {}; | ^^^^^^^ not allowed after `pat` fragments @@ -71,7 +71,7 @@ LL | ($p:pat $e:expr) => {}; = note: allowed there are: `=>`, `,`, `=`, `|`, `if`, `if let` or `in` error: `$p:pat` is followed by `$t:ty`, which is not allowed for `pat` fragments - --> $DIR/macro-follow.rs:19:13 + --> $DIR/macro-follow.rs:21:13 | LL | ($p:pat $t:ty) => {}; | ^^^^^ not allowed after `pat` fragments @@ -79,7 +79,7 @@ LL | ($p:pat $t:ty) => {}; = note: allowed there are: `=>`, `,`, `=`, `|`, `if`, `if let` or `in` error: `$p:pat` is followed by `$s:stmt`, which is not allowed for `pat` fragments - --> $DIR/macro-follow.rs:20:13 + --> $DIR/macro-follow.rs:22:13 | LL | ($p:pat $s:stmt) => {}; | ^^^^^^^ not allowed after `pat` fragments @@ -87,7 +87,7 @@ LL | ($p:pat $s:stmt) => {}; = note: allowed there are: `=>`, `,`, `=`, `|`, `if`, `if let` or `in` error: `$p:pat` is followed by `$q:path`, which is not allowed for `pat` fragments - --> $DIR/macro-follow.rs:21:13 + --> $DIR/macro-follow.rs:23:13 | LL | ($p:pat $q:path) => {}; | ^^^^^^^ not allowed after `pat` fragments @@ -95,7 +95,7 @@ LL | ($p:pat $q:path) => {}; = note: allowed there are: `=>`, `,`, `=`, `|`, `if`, `if let` or `in` error: `$p:pat` is followed by `$b:block`, which is not allowed for `pat` fragments - --> $DIR/macro-follow.rs:22:13 + --> $DIR/macro-follow.rs:24:13 | LL | ($p:pat $b:block) => {}; | ^^^^^^^^ not allowed after `pat` fragments @@ -103,7 +103,7 @@ LL | ($p:pat $b:block) => {}; = note: allowed there are: `=>`, `,`, `=`, `|`, `if`, `if let` or `in` error: `$p:pat` is followed by `$i:ident`, which is not allowed for `pat` fragments - --> $DIR/macro-follow.rs:23:13 + --> $DIR/macro-follow.rs:25:13 | LL | ($p:pat $i:ident) => {}; | ^^^^^^^^ not allowed after `pat` fragments @@ -111,7 +111,7 @@ LL | ($p:pat $i:ident) => {}; = note: allowed there are: `=>`, `,`, `=`, `|`, `if`, `if let` or `in` error: `$p:pat` is followed by `$t:tt`, which is not allowed for `pat` fragments - --> $DIR/macro-follow.rs:24:13 + --> $DIR/macro-follow.rs:26:13 | LL | ($p:pat $t:tt) => {}; | ^^^^^ not allowed after `pat` fragments @@ -119,7 +119,7 @@ LL | ($p:pat $t:tt) => {}; = note: allowed there are: `=>`, `,`, `=`, `|`, `if`, `if let` or `in` error: `$p:pat` is followed by `$i:item`, which is not allowed for `pat` fragments - --> $DIR/macro-follow.rs:25:13 + --> $DIR/macro-follow.rs:27:13 | LL | ($p:pat $i:item) => {}; | ^^^^^^^ not allowed after `pat` fragments @@ -127,7 +127,7 @@ LL | ($p:pat $i:item) => {}; = note: allowed there are: `=>`, `,`, `=`, `|`, `if`, `if let` or `in` error: `$p:pat` is followed by `$m:meta`, which is not allowed for `pat` fragments - --> $DIR/macro-follow.rs:26:13 + --> $DIR/macro-follow.rs:28:13 | LL | ($p:pat $m:meta) => {}; | ^^^^^^^ not allowed after `pat` fragments @@ -135,7 +135,7 @@ LL | ($p:pat $m:meta) => {}; = note: allowed there are: `=>`, `,`, `=`, `|`, `if`, `if let` or `in` error: `$e:expr` is followed by `(`, which is not allowed for `expr` fragments - --> $DIR/macro-follow.rs:30:14 + --> $DIR/macro-follow.rs:32:14 | LL | ($e:expr ()) => {}; | ^ not allowed after `expr` fragments @@ -143,7 +143,7 @@ LL | ($e:expr ()) => {}; = note: allowed there are: `=>`, `,` or `;` error: `$e:expr` is followed by `[`, which is not allowed for `expr` fragments - --> $DIR/macro-follow.rs:31:14 + --> $DIR/macro-follow.rs:33:14 | LL | ($e:expr []) => {}; | ^ not allowed after `expr` fragments @@ -151,7 +151,7 @@ LL | ($e:expr []) => {}; = note: allowed there are: `=>`, `,` or `;` error: `$e:expr` is followed by `{`, which is not allowed for `expr` fragments - --> $DIR/macro-follow.rs:32:14 + --> $DIR/macro-follow.rs:34:14 | LL | ($e:expr {}) => {}; | ^ not allowed after `expr` fragments @@ -159,7 +159,7 @@ LL | ($e:expr {}) => {}; = note: allowed there are: `=>`, `,` or `;` error: `$e:expr` is followed by `=`, which is not allowed for `expr` fragments - --> $DIR/macro-follow.rs:33:14 + --> $DIR/macro-follow.rs:35:14 | LL | ($e:expr =) => {}; | ^ not allowed after `expr` fragments @@ -167,7 +167,7 @@ LL | ($e:expr =) => {}; = note: allowed there are: `=>`, `,` or `;` error: `$e:expr` is followed by `|`, which is not allowed for `expr` fragments - --> $DIR/macro-follow.rs:34:14 + --> $DIR/macro-follow.rs:36:14 | LL | ($e:expr |) => {}; | ^ not allowed after `expr` fragments @@ -175,7 +175,7 @@ LL | ($e:expr |) => {}; = note: allowed there are: `=>`, `,` or `;` error: `$e:expr` is followed by `:`, which is not allowed for `expr` fragments - --> $DIR/macro-follow.rs:35:14 + --> $DIR/macro-follow.rs:37:14 | LL | ($e:expr :) => {}; | ^ not allowed after `expr` fragments @@ -183,7 +183,7 @@ LL | ($e:expr :) => {}; = note: allowed there are: `=>`, `,` or `;` error: `$e:expr` is followed by `>`, which is not allowed for `expr` fragments - --> $DIR/macro-follow.rs:36:14 + --> $DIR/macro-follow.rs:38:14 | LL | ($e:expr >) => {}; | ^ not allowed after `expr` fragments @@ -191,7 +191,7 @@ LL | ($e:expr >) => {}; = note: allowed there are: `=>`, `,` or `;` error: `$e:expr` is followed by `+`, which is not allowed for `expr` fragments - --> $DIR/macro-follow.rs:37:14 + --> $DIR/macro-follow.rs:39:14 | LL | ($e:expr +) => {}; | ^ not allowed after `expr` fragments @@ -199,7 +199,7 @@ LL | ($e:expr +) => {}; = note: allowed there are: `=>`, `,` or `;` error: `$e:expr` is followed by `ident`, which is not allowed for `expr` fragments - --> $DIR/macro-follow.rs:38:14 + --> $DIR/macro-follow.rs:40:14 | LL | ($e:expr ident) => {}; | ^^^^^ not allowed after `expr` fragments @@ -207,7 +207,7 @@ LL | ($e:expr ident) => {}; = note: allowed there are: `=>`, `,` or `;` error: `$e:expr` is followed by `if`, which is not allowed for `expr` fragments - --> $DIR/macro-follow.rs:39:14 + --> $DIR/macro-follow.rs:41:14 | LL | ($e:expr if) => {}; | ^^ not allowed after `expr` fragments @@ -215,7 +215,7 @@ LL | ($e:expr if) => {}; = note: allowed there are: `=>`, `,` or `;` error: `$e:expr` is followed by `in`, which is not allowed for `expr` fragments - --> $DIR/macro-follow.rs:40:14 + --> $DIR/macro-follow.rs:42:14 | LL | ($e:expr in) => {}; | ^^ not allowed after `expr` fragments @@ -223,7 +223,7 @@ LL | ($e:expr in) => {}; = note: allowed there are: `=>`, `,` or `;` error: `$e:expr` is followed by `$p:pat`, which is not allowed for `expr` fragments - --> $DIR/macro-follow.rs:41:14 + --> $DIR/macro-follow.rs:43:14 | LL | ($e:expr $p:pat) => {}; | ^^^^^^ not allowed after `expr` fragments @@ -231,7 +231,7 @@ LL | ($e:expr $p:pat) => {}; = note: allowed there are: `=>`, `,` or `;` error: `$e:expr` is followed by `$f:expr`, which is not allowed for `expr` fragments - --> $DIR/macro-follow.rs:42:14 + --> $DIR/macro-follow.rs:44:14 | LL | ($e:expr $f:expr) => {}; | ^^^^^^^ not allowed after `expr` fragments @@ -239,7 +239,7 @@ LL | ($e:expr $f:expr) => {}; = note: allowed there are: `=>`, `,` or `;` error: `$e:expr` is followed by `$t:ty`, which is not allowed for `expr` fragments - --> $DIR/macro-follow.rs:43:14 + --> $DIR/macro-follow.rs:45:14 | LL | ($e:expr $t:ty) => {}; | ^^^^^ not allowed after `expr` fragments @@ -247,7 +247,7 @@ LL | ($e:expr $t:ty) => {}; = note: allowed there are: `=>`, `,` or `;` error: `$e:expr` is followed by `$s:stmt`, which is not allowed for `expr` fragments - --> $DIR/macro-follow.rs:44:14 + --> $DIR/macro-follow.rs:46:14 | LL | ($e:expr $s:stmt) => {}; | ^^^^^^^ not allowed after `expr` fragments @@ -255,7 +255,7 @@ LL | ($e:expr $s:stmt) => {}; = note: allowed there are: `=>`, `,` or `;` error: `$e:expr` is followed by `$p:path`, which is not allowed for `expr` fragments - --> $DIR/macro-follow.rs:45:14 + --> $DIR/macro-follow.rs:47:14 | LL | ($e:expr $p:path) => {}; | ^^^^^^^ not allowed after `expr` fragments @@ -263,7 +263,7 @@ LL | ($e:expr $p:path) => {}; = note: allowed there are: `=>`, `,` or `;` error: `$e:expr` is followed by `$b:block`, which is not allowed for `expr` fragments - --> $DIR/macro-follow.rs:46:14 + --> $DIR/macro-follow.rs:48:14 | LL | ($e:expr $b:block) => {}; | ^^^^^^^^ not allowed after `expr` fragments @@ -271,7 +271,7 @@ LL | ($e:expr $b:block) => {}; = note: allowed there are: `=>`, `,` or `;` error: `$e:expr` is followed by `$i:ident`, which is not allowed for `expr` fragments - --> $DIR/macro-follow.rs:47:14 + --> $DIR/macro-follow.rs:49:14 | LL | ($e:expr $i:ident) => {}; | ^^^^^^^^ not allowed after `expr` fragments @@ -279,7 +279,7 @@ LL | ($e:expr $i:ident) => {}; = note: allowed there are: `=>`, `,` or `;` error: `$e:expr` is followed by `$t:tt`, which is not allowed for `expr` fragments - --> $DIR/macro-follow.rs:48:14 + --> $DIR/macro-follow.rs:50:14 | LL | ($e:expr $t:tt) => {}; | ^^^^^ not allowed after `expr` fragments @@ -287,7 +287,7 @@ LL | ($e:expr $t:tt) => {}; = note: allowed there are: `=>`, `,` or `;` error: `$e:expr` is followed by `$i:item`, which is not allowed for `expr` fragments - --> $DIR/macro-follow.rs:49:14 + --> $DIR/macro-follow.rs:51:14 | LL | ($e:expr $i:item) => {}; | ^^^^^^^ not allowed after `expr` fragments @@ -295,7 +295,7 @@ LL | ($e:expr $i:item) => {}; = note: allowed there are: `=>`, `,` or `;` error: `$e:expr` is followed by `$m:meta`, which is not allowed for `expr` fragments - --> $DIR/macro-follow.rs:50:14 + --> $DIR/macro-follow.rs:52:14 | LL | ($e:expr $m:meta) => {}; | ^^^^^^^ not allowed after `expr` fragments @@ -303,7 +303,7 @@ LL | ($e:expr $m:meta) => {}; = note: allowed there are: `=>`, `,` or `;` error: `$e:expr` is followed by `$g:guard`, which is not allowed for `expr` fragments - --> $DIR/macro-follow.rs:51:14 + --> $DIR/macro-follow.rs:53:14 | LL | ($e:expr $g:guard) => {}; | ^^^^^^^^ not allowed after `expr` fragments @@ -311,7 +311,7 @@ LL | ($e:expr $g:guard) => {}; = note: allowed there are: `=>`, `,` or `;` error: `$t:ty` is followed by `(`, which is not allowed for `ty` fragments - --> $DIR/macro-follow.rs:56:12 + --> $DIR/macro-follow.rs:58:12 | LL | ($t:ty ()) => {}; | ^ not allowed after `ty` fragments @@ -319,7 +319,7 @@ LL | ($t:ty ()) => {}; = note: allowed there are: `{`, `[`, `=>`, `,`, `>`, `=`, `:`, `;`, `|`, `as` or `where` error: `$t:ty` is followed by `+`, which is not allowed for `ty` fragments - --> $DIR/macro-follow.rs:58:12 + --> $DIR/macro-follow.rs:60:12 | LL | ($t:ty +) => {}; | ^ not allowed after `ty` fragments @@ -327,7 +327,7 @@ LL | ($t:ty +) => {}; = note: allowed there are: `{`, `[`, `=>`, `,`, `>`, `=`, `:`, `;`, `|`, `as` or `where` error: `$t:ty` is followed by `ident`, which is not allowed for `ty` fragments - --> $DIR/macro-follow.rs:59:12 + --> $DIR/macro-follow.rs:61:12 | LL | ($t:ty ident) => {}; | ^^^^^ not allowed after `ty` fragments @@ -335,7 +335,7 @@ LL | ($t:ty ident) => {}; = note: allowed there are: `{`, `[`, `=>`, `,`, `>`, `=`, `:`, `;`, `|`, `as` or `where` error: `$t:ty` is followed by `if`, which is not allowed for `ty` fragments - --> $DIR/macro-follow.rs:60:12 + --> $DIR/macro-follow.rs:62:12 | LL | ($t:ty if) => {}; | ^^ not allowed after `ty` fragments @@ -343,7 +343,7 @@ LL | ($t:ty if) => {}; = note: allowed there are: `{`, `[`, `=>`, `,`, `>`, `=`, `:`, `;`, `|`, `as` or `where` error: `$t:ty` is followed by `$p:pat`, which is not allowed for `ty` fragments - --> $DIR/macro-follow.rs:61:12 + --> $DIR/macro-follow.rs:63:12 | LL | ($t:ty $p:pat) => {}; | ^^^^^^ not allowed after `ty` fragments @@ -351,7 +351,7 @@ LL | ($t:ty $p:pat) => {}; = note: allowed there are: `{`, `[`, `=>`, `,`, `>`, `=`, `:`, `;`, `|`, `as` or `where` error: `$t:ty` is followed by `$e:expr`, which is not allowed for `ty` fragments - --> $DIR/macro-follow.rs:62:12 + --> $DIR/macro-follow.rs:64:12 | LL | ($t:ty $e:expr) => {}; | ^^^^^^^ not allowed after `ty` fragments @@ -359,7 +359,7 @@ LL | ($t:ty $e:expr) => {}; = note: allowed there are: `{`, `[`, `=>`, `,`, `>`, `=`, `:`, `;`, `|`, `as` or `where` error: `$t:ty` is followed by `$r:ty`, which is not allowed for `ty` fragments - --> $DIR/macro-follow.rs:63:12 + --> $DIR/macro-follow.rs:65:12 | LL | ($t:ty $r:ty) => {}; | ^^^^^ not allowed after `ty` fragments @@ -367,7 +367,7 @@ LL | ($t:ty $r:ty) => {}; = note: allowed there are: `{`, `[`, `=>`, `,`, `>`, `=`, `:`, `;`, `|`, `as` or `where` error: `$t:ty` is followed by `$s:stmt`, which is not allowed for `ty` fragments - --> $DIR/macro-follow.rs:64:12 + --> $DIR/macro-follow.rs:66:12 | LL | ($t:ty $s:stmt) => {}; | ^^^^^^^ not allowed after `ty` fragments @@ -375,7 +375,7 @@ LL | ($t:ty $s:stmt) => {}; = note: allowed there are: `{`, `[`, `=>`, `,`, `>`, `=`, `:`, `;`, `|`, `as` or `where` error: `$t:ty` is followed by `$p:path`, which is not allowed for `ty` fragments - --> $DIR/macro-follow.rs:65:12 + --> $DIR/macro-follow.rs:67:12 | LL | ($t:ty $p:path) => {}; | ^^^^^^^ not allowed after `ty` fragments @@ -383,7 +383,7 @@ LL | ($t:ty $p:path) => {}; = note: allowed there are: `{`, `[`, `=>`, `,`, `>`, `=`, `:`, `;`, `|`, `as` or `where` error: `$t:ty` is followed by `$i:ident`, which is not allowed for `ty` fragments - --> $DIR/macro-follow.rs:67:12 + --> $DIR/macro-follow.rs:69:12 | LL | ($t:ty $i:ident) => {}; | ^^^^^^^^ not allowed after `ty` fragments @@ -391,7 +391,7 @@ LL | ($t:ty $i:ident) => {}; = note: allowed there are: `{`, `[`, `=>`, `,`, `>`, `=`, `:`, `;`, `|`, `as` or `where` error: `$t:ty` is followed by `$r:tt`, which is not allowed for `ty` fragments - --> $DIR/macro-follow.rs:68:12 + --> $DIR/macro-follow.rs:70:12 | LL | ($t:ty $r:tt) => {}; | ^^^^^ not allowed after `ty` fragments @@ -399,7 +399,7 @@ LL | ($t:ty $r:tt) => {}; = note: allowed there are: `{`, `[`, `=>`, `,`, `>`, `=`, `:`, `;`, `|`, `as` or `where` error: `$t:ty` is followed by `$i:item`, which is not allowed for `ty` fragments - --> $DIR/macro-follow.rs:69:12 + --> $DIR/macro-follow.rs:71:12 | LL | ($t:ty $i:item) => {}; | ^^^^^^^ not allowed after `ty` fragments @@ -407,7 +407,7 @@ LL | ($t:ty $i:item) => {}; = note: allowed there are: `{`, `[`, `=>`, `,`, `>`, `=`, `:`, `;`, `|`, `as` or `where` error: `$t:ty` is followed by `$m:meta`, which is not allowed for `ty` fragments - --> $DIR/macro-follow.rs:70:12 + --> $DIR/macro-follow.rs:72:12 | LL | ($t:ty $m:meta) => {}; | ^^^^^^^ not allowed after `ty` fragments @@ -415,7 +415,7 @@ LL | ($t:ty $m:meta) => {}; = note: allowed there are: `{`, `[`, `=>`, `,`, `>`, `=`, `:`, `;`, `|`, `as` or `where` error: `$t:ty` is followed by `$g:guard`, which is not allowed for `ty` fragments - --> $DIR/macro-follow.rs:71:12 + --> $DIR/macro-follow.rs:73:12 | LL | ($t:ty $g:guard) => {}; | ^^^^^^^^ not allowed after `ty` fragments @@ -423,7 +423,7 @@ LL | ($t:ty $g:guard) => {}; = note: allowed there are: `{`, `[`, `=>`, `,`, `>`, `=`, `:`, `;`, `|`, `as` or `where` error: `$s:stmt` is followed by `(`, which is not allowed for `stmt` fragments - --> $DIR/macro-follow.rs:75:14 + --> $DIR/macro-follow.rs:77:14 | LL | ($s:stmt ()) => {}; | ^ not allowed after `stmt` fragments @@ -431,7 +431,7 @@ LL | ($s:stmt ()) => {}; = note: allowed there are: `=>`, `,` or `;` error: `$s:stmt` is followed by `[`, which is not allowed for `stmt` fragments - --> $DIR/macro-follow.rs:76:14 + --> $DIR/macro-follow.rs:78:14 | LL | ($s:stmt []) => {}; | ^ not allowed after `stmt` fragments @@ -439,7 +439,7 @@ LL | ($s:stmt []) => {}; = note: allowed there are: `=>`, `,` or `;` error: `$s:stmt` is followed by `{`, which is not allowed for `stmt` fragments - --> $DIR/macro-follow.rs:77:14 + --> $DIR/macro-follow.rs:79:14 | LL | ($s:stmt {}) => {}; | ^ not allowed after `stmt` fragments @@ -447,7 +447,7 @@ LL | ($s:stmt {}) => {}; = note: allowed there are: `=>`, `,` or `;` error: `$s:stmt` is followed by `=`, which is not allowed for `stmt` fragments - --> $DIR/macro-follow.rs:78:14 + --> $DIR/macro-follow.rs:80:14 | LL | ($s:stmt =) => {}; | ^ not allowed after `stmt` fragments @@ -455,7 +455,7 @@ LL | ($s:stmt =) => {}; = note: allowed there are: `=>`, `,` or `;` error: `$s:stmt` is followed by `|`, which is not allowed for `stmt` fragments - --> $DIR/macro-follow.rs:79:14 + --> $DIR/macro-follow.rs:81:14 | LL | ($s:stmt |) => {}; | ^ not allowed after `stmt` fragments @@ -463,7 +463,7 @@ LL | ($s:stmt |) => {}; = note: allowed there are: `=>`, `,` or `;` error: `$s:stmt` is followed by `:`, which is not allowed for `stmt` fragments - --> $DIR/macro-follow.rs:80:14 + --> $DIR/macro-follow.rs:82:14 | LL | ($s:stmt :) => {}; | ^ not allowed after `stmt` fragments @@ -471,7 +471,7 @@ LL | ($s:stmt :) => {}; = note: allowed there are: `=>`, `,` or `;` error: `$s:stmt` is followed by `>`, which is not allowed for `stmt` fragments - --> $DIR/macro-follow.rs:81:14 + --> $DIR/macro-follow.rs:83:14 | LL | ($s:stmt >) => {}; | ^ not allowed after `stmt` fragments @@ -479,7 +479,7 @@ LL | ($s:stmt >) => {}; = note: allowed there are: `=>`, `,` or `;` error: `$s:stmt` is followed by `+`, which is not allowed for `stmt` fragments - --> $DIR/macro-follow.rs:82:14 + --> $DIR/macro-follow.rs:84:14 | LL | ($s:stmt +) => {}; | ^ not allowed after `stmt` fragments @@ -487,7 +487,7 @@ LL | ($s:stmt +) => {}; = note: allowed there are: `=>`, `,` or `;` error: `$s:stmt` is followed by `ident`, which is not allowed for `stmt` fragments - --> $DIR/macro-follow.rs:83:14 + --> $DIR/macro-follow.rs:85:14 | LL | ($s:stmt ident) => {}; | ^^^^^ not allowed after `stmt` fragments @@ -495,7 +495,7 @@ LL | ($s:stmt ident) => {}; = note: allowed there are: `=>`, `,` or `;` error: `$s:stmt` is followed by `if`, which is not allowed for `stmt` fragments - --> $DIR/macro-follow.rs:84:14 + --> $DIR/macro-follow.rs:86:14 | LL | ($s:stmt if) => {}; | ^^ not allowed after `stmt` fragments @@ -503,7 +503,7 @@ LL | ($s:stmt if) => {}; = note: allowed there are: `=>`, `,` or `;` error: `$s:stmt` is followed by `in`, which is not allowed for `stmt` fragments - --> $DIR/macro-follow.rs:85:14 + --> $DIR/macro-follow.rs:87:14 | LL | ($s:stmt in) => {}; | ^^ not allowed after `stmt` fragments @@ -511,7 +511,7 @@ LL | ($s:stmt in) => {}; = note: allowed there are: `=>`, `,` or `;` error: `$s:stmt` is followed by `$p:pat`, which is not allowed for `stmt` fragments - --> $DIR/macro-follow.rs:86:14 + --> $DIR/macro-follow.rs:88:14 | LL | ($s:stmt $p:pat) => {}; | ^^^^^^ not allowed after `stmt` fragments @@ -519,7 +519,7 @@ LL | ($s:stmt $p:pat) => {}; = note: allowed there are: `=>`, `,` or `;` error: `$s:stmt` is followed by `$e:expr`, which is not allowed for `stmt` fragments - --> $DIR/macro-follow.rs:87:14 + --> $DIR/macro-follow.rs:89:14 | LL | ($s:stmt $e:expr) => {}; | ^^^^^^^ not allowed after `stmt` fragments @@ -527,7 +527,7 @@ LL | ($s:stmt $e:expr) => {}; = note: allowed there are: `=>`, `,` or `;` error: `$s:stmt` is followed by `$t:ty`, which is not allowed for `stmt` fragments - --> $DIR/macro-follow.rs:88:14 + --> $DIR/macro-follow.rs:90:14 | LL | ($s:stmt $t:ty) => {}; | ^^^^^ not allowed after `stmt` fragments @@ -535,7 +535,7 @@ LL | ($s:stmt $t:ty) => {}; = note: allowed there are: `=>`, `,` or `;` error: `$s:stmt` is followed by `$t:stmt`, which is not allowed for `stmt` fragments - --> $DIR/macro-follow.rs:89:14 + --> $DIR/macro-follow.rs:91:14 | LL | ($s:stmt $t:stmt) => {}; | ^^^^^^^ not allowed after `stmt` fragments @@ -543,7 +543,7 @@ LL | ($s:stmt $t:stmt) => {}; = note: allowed there are: `=>`, `,` or `;` error: `$s:stmt` is followed by `$p:path`, which is not allowed for `stmt` fragments - --> $DIR/macro-follow.rs:90:14 + --> $DIR/macro-follow.rs:92:14 | LL | ($s:stmt $p:path) => {}; | ^^^^^^^ not allowed after `stmt` fragments @@ -551,7 +551,7 @@ LL | ($s:stmt $p:path) => {}; = note: allowed there are: `=>`, `,` or `;` error: `$s:stmt` is followed by `$b:block`, which is not allowed for `stmt` fragments - --> $DIR/macro-follow.rs:91:14 + --> $DIR/macro-follow.rs:93:14 | LL | ($s:stmt $b:block) => {}; | ^^^^^^^^ not allowed after `stmt` fragments @@ -559,7 +559,7 @@ LL | ($s:stmt $b:block) => {}; = note: allowed there are: `=>`, `,` or `;` error: `$s:stmt` is followed by `$i:ident`, which is not allowed for `stmt` fragments - --> $DIR/macro-follow.rs:92:14 + --> $DIR/macro-follow.rs:94:14 | LL | ($s:stmt $i:ident) => {}; | ^^^^^^^^ not allowed after `stmt` fragments @@ -567,7 +567,7 @@ LL | ($s:stmt $i:ident) => {}; = note: allowed there are: `=>`, `,` or `;` error: `$s:stmt` is followed by `$t:tt`, which is not allowed for `stmt` fragments - --> $DIR/macro-follow.rs:93:14 + --> $DIR/macro-follow.rs:95:14 | LL | ($s:stmt $t:tt) => {}; | ^^^^^ not allowed after `stmt` fragments @@ -575,7 +575,7 @@ LL | ($s:stmt $t:tt) => {}; = note: allowed there are: `=>`, `,` or `;` error: `$s:stmt` is followed by `$i:item`, which is not allowed for `stmt` fragments - --> $DIR/macro-follow.rs:94:14 + --> $DIR/macro-follow.rs:96:14 | LL | ($s:stmt $i:item) => {}; | ^^^^^^^ not allowed after `stmt` fragments @@ -583,7 +583,7 @@ LL | ($s:stmt $i:item) => {}; = note: allowed there are: `=>`, `,` or `;` error: `$s:stmt` is followed by `$m:meta`, which is not allowed for `stmt` fragments - --> $DIR/macro-follow.rs:95:14 + --> $DIR/macro-follow.rs:97:14 | LL | ($s:stmt $m:meta) => {}; | ^^^^^^^ not allowed after `stmt` fragments @@ -591,7 +591,7 @@ LL | ($s:stmt $m:meta) => {}; = note: allowed there are: `=>`, `,` or `;` error: `$s:stmt` is followed by `$g:guard`, which is not allowed for `stmt` fragments - --> $DIR/macro-follow.rs:96:14 + --> $DIR/macro-follow.rs:98:14 | LL | ($s:stmt $g:guard) => {}; | ^^^^^^^^ not allowed after `stmt` fragments @@ -599,7 +599,7 @@ LL | ($s:stmt $g:guard) => {}; = note: allowed there are: `=>`, `,` or `;` error: `$p:path` is followed by `(`, which is not allowed for `path` fragments - --> $DIR/macro-follow.rs:100:14 + --> $DIR/macro-follow.rs:102:14 | LL | ($p:path ()) => {}; | ^ not allowed after `path` fragments @@ -607,7 +607,7 @@ LL | ($p:path ()) => {}; = note: allowed there are: `{`, `[`, `=>`, `,`, `>`, `=`, `:`, `;`, `|`, `as` or `where` error: `$p:path` is followed by `+`, which is not allowed for `path` fragments - --> $DIR/macro-follow.rs:102:14 + --> $DIR/macro-follow.rs:104:14 | LL | ($p:path +) => {}; | ^ not allowed after `path` fragments @@ -615,7 +615,7 @@ LL | ($p:path +) => {}; = note: allowed there are: `{`, `[`, `=>`, `,`, `>`, `=`, `:`, `;`, `|`, `as` or `where` error: `$p:path` is followed by `ident`, which is not allowed for `path` fragments - --> $DIR/macro-follow.rs:103:14 + --> $DIR/macro-follow.rs:105:14 | LL | ($p:path ident) => {}; | ^^^^^ not allowed after `path` fragments @@ -623,7 +623,7 @@ LL | ($p:path ident) => {}; = note: allowed there are: `{`, `[`, `=>`, `,`, `>`, `=`, `:`, `;`, `|`, `as` or `where` error: `$p:path` is followed by `if`, which is not allowed for `path` fragments - --> $DIR/macro-follow.rs:104:14 + --> $DIR/macro-follow.rs:106:14 | LL | ($p:path if) => {}; | ^^ not allowed after `path` fragments @@ -631,7 +631,7 @@ LL | ($p:path if) => {}; = note: allowed there are: `{`, `[`, `=>`, `,`, `>`, `=`, `:`, `;`, `|`, `as` or `where` error: `$p:path` is followed by `$q:pat`, which is not allowed for `path` fragments - --> $DIR/macro-follow.rs:105:14 + --> $DIR/macro-follow.rs:107:14 | LL | ($p:path $q:pat) => {}; | ^^^^^^ not allowed after `path` fragments @@ -639,7 +639,7 @@ LL | ($p:path $q:pat) => {}; = note: allowed there are: `{`, `[`, `=>`, `,`, `>`, `=`, `:`, `;`, `|`, `as` or `where` error: `$p:path` is followed by `$e:expr`, which is not allowed for `path` fragments - --> $DIR/macro-follow.rs:106:14 + --> $DIR/macro-follow.rs:108:14 | LL | ($p:path $e:expr) => {}; | ^^^^^^^ not allowed after `path` fragments @@ -647,7 +647,7 @@ LL | ($p:path $e:expr) => {}; = note: allowed there are: `{`, `[`, `=>`, `,`, `>`, `=`, `:`, `;`, `|`, `as` or `where` error: `$p:path` is followed by `$t:ty`, which is not allowed for `path` fragments - --> $DIR/macro-follow.rs:107:14 + --> $DIR/macro-follow.rs:109:14 | LL | ($p:path $t:ty) => {}; | ^^^^^ not allowed after `path` fragments @@ -655,7 +655,7 @@ LL | ($p:path $t:ty) => {}; = note: allowed there are: `{`, `[`, `=>`, `,`, `>`, `=`, `:`, `;`, `|`, `as` or `where` error: `$p:path` is followed by `$s:stmt`, which is not allowed for `path` fragments - --> $DIR/macro-follow.rs:108:14 + --> $DIR/macro-follow.rs:110:14 | LL | ($p:path $s:stmt) => {}; | ^^^^^^^ not allowed after `path` fragments @@ -663,7 +663,7 @@ LL | ($p:path $s:stmt) => {}; = note: allowed there are: `{`, `[`, `=>`, `,`, `>`, `=`, `:`, `;`, `|`, `as` or `where` error: `$p:path` is followed by `$q:path`, which is not allowed for `path` fragments - --> $DIR/macro-follow.rs:109:14 + --> $DIR/macro-follow.rs:111:14 | LL | ($p:path $q:path) => {}; | ^^^^^^^ not allowed after `path` fragments @@ -671,7 +671,7 @@ LL | ($p:path $q:path) => {}; = note: allowed there are: `{`, `[`, `=>`, `,`, `>`, `=`, `:`, `;`, `|`, `as` or `where` error: `$p:path` is followed by `$i:ident`, which is not allowed for `path` fragments - --> $DIR/macro-follow.rs:111:14 + --> $DIR/macro-follow.rs:113:14 | LL | ($p:path $i:ident) => {}; | ^^^^^^^^ not allowed after `path` fragments @@ -679,7 +679,7 @@ LL | ($p:path $i:ident) => {}; = note: allowed there are: `{`, `[`, `=>`, `,`, `>`, `=`, `:`, `;`, `|`, `as` or `where` error: `$p:path` is followed by `$t:tt`, which is not allowed for `path` fragments - --> $DIR/macro-follow.rs:112:14 + --> $DIR/macro-follow.rs:114:14 | LL | ($p:path $t:tt) => {}; | ^^^^^ not allowed after `path` fragments @@ -687,7 +687,7 @@ LL | ($p:path $t:tt) => {}; = note: allowed there are: `{`, `[`, `=>`, `,`, `>`, `=`, `:`, `;`, `|`, `as` or `where` error: `$p:path` is followed by `$i:item`, which is not allowed for `path` fragments - --> $DIR/macro-follow.rs:113:14 + --> $DIR/macro-follow.rs:115:14 | LL | ($p:path $i:item) => {}; | ^^^^^^^ not allowed after `path` fragments @@ -695,7 +695,7 @@ LL | ($p:path $i:item) => {}; = note: allowed there are: `{`, `[`, `=>`, `,`, `>`, `=`, `:`, `;`, `|`, `as` or `where` error: `$p:path` is followed by `$m:meta`, which is not allowed for `path` fragments - --> $DIR/macro-follow.rs:114:14 + --> $DIR/macro-follow.rs:116:14 | LL | ($p:path $m:meta) => {}; | ^^^^^^^ not allowed after `path` fragments @@ -703,7 +703,7 @@ LL | ($p:path $m:meta) => {}; = note: allowed there are: `{`, `[`, `=>`, `,`, `>`, `=`, `:`, `;`, `|`, `as` or `where` error: `$p:path` is followed by `$g:guard`, which is not allowed for `path` fragments - --> $DIR/macro-follow.rs:115:14 + --> $DIR/macro-follow.rs:117:14 | LL | ($p:path $g:guard) => {}; | ^^^^^^^^ not allowed after `path` fragments diff --git a/tests/ui/macros/macro-followed-by-seq-bad.rs b/tests/ui/macros/macro-followed-by-seq-bad.rs index b73742f77ea58..ba72a6504885a 100644 --- a/tests/ui/macros/macro-followed-by-seq-bad.rs +++ b/tests/ui/macros/macro-followed-by-seq-bad.rs @@ -1,3 +1,4 @@ +//@ reference: macro.decl.follow-set.repetition // Regression test for issue #25436: check that things which can be // followed by any token also permit X* to come afterwards. diff --git a/tests/ui/macros/macro-followed-by-seq-bad.stderr b/tests/ui/macros/macro-followed-by-seq-bad.stderr index 7097979aeddf3..1621bd8ccf405 100644 --- a/tests/ui/macros/macro-followed-by-seq-bad.stderr +++ b/tests/ui/macros/macro-followed-by-seq-bad.stderr @@ -1,5 +1,5 @@ error: `$a:expr` is followed by `$b:tt`, which is not allowed for `expr` fragments - --> $DIR/macro-followed-by-seq-bad.rs:7:15 + --> $DIR/macro-followed-by-seq-bad.rs:8:15 | LL | ( $a:expr $($b:tt)* ) => { }; | ^^^^^ not allowed after `expr` fragments @@ -7,7 +7,7 @@ LL | ( $a:expr $($b:tt)* ) => { }; = note: allowed there are: `=>`, `,` or `;` error: `$a:ty` is followed by `$b:tt`, which is not allowed for `ty` fragments - --> $DIR/macro-followed-by-seq-bad.rs:8:13 + --> $DIR/macro-followed-by-seq-bad.rs:9:13 | LL | ( $a:ty $($b:tt)* ) => { }; | ^^^^^ not allowed after `ty` fragments diff --git a/tests/ui/macros/macro-followed-by-seq.rs b/tests/ui/macros/macro-followed-by-seq.rs index 3643836fa031f..1c61a4493fdec 100644 --- a/tests/ui/macros/macro-followed-by-seq.rs +++ b/tests/ui/macros/macro-followed-by-seq.rs @@ -1,4 +1,5 @@ //@ check-pass +//@ reference: macro.decl.follow-set.repetition #![allow(unused_macros)] // Regression test for issue #25436: check that things which can be // followed by any token also permit X* to come afterwards. diff --git a/tests/ui/macros/macro-hygiene-help-issue-148580.rs b/tests/ui/macros/macro-hygiene-help-issue-148580.rs index 8441290b17228..7f834c28c0989 100644 --- a/tests/ui/macros/macro-hygiene-help-issue-148580.rs +++ b/tests/ui/macros/macro-hygiene-help-issue-148580.rs @@ -1,3 +1,4 @@ +//@ reference: macro.decl.hygiene.intro macro_rules! print_it { {} => { println!("{:?}", it); } } //~^ ERROR cannot find value `it` in this scope diff --git a/tests/ui/macros/macro-hygiene-help-issue-148580.stderr b/tests/ui/macros/macro-hygiene-help-issue-148580.stderr index f6a4ae7dd1c66..56e021078855e 100644 --- a/tests/ui/macros/macro-hygiene-help-issue-148580.stderr +++ b/tests/ui/macros/macro-hygiene-help-issue-148580.stderr @@ -1,5 +1,5 @@ error[E0425]: cannot find value `it` in this scope - --> $DIR/macro-hygiene-help-issue-148580.rs:1:50 + --> $DIR/macro-hygiene-help-issue-148580.rs:2:50 | LL | macro_rules! print_it { {} => { println!("{:?}", it); } } | ^^ not found in this scope @@ -8,7 +8,7 @@ LL | print_it!(); | ----------- in this macro invocation | help: an identifier with the same name exists, but is not accessible due to macro hygiene - --> $DIR/macro-hygiene-help-issue-148580.rs:11:17 + --> $DIR/macro-hygiene-help-issue-148580.rs:12:17 | LL | let it = (); | ^^ diff --git a/tests/ui/macros/macro-hygiene-help-issue-149604.rs b/tests/ui/macros/macro-hygiene-help-issue-149604.rs index 5700218cc8671..2c01230fbe5df 100644 --- a/tests/ui/macros/macro-hygiene-help-issue-149604.rs +++ b/tests/ui/macros/macro-hygiene-help-issue-149604.rs @@ -1,3 +1,4 @@ +//@ reference: macro.decl.hygiene.intro macro_rules! let_it { {} => { let it = (); } } macro_rules! print_it { {} => { println!("{:?}", it); } } //~^ ERROR cannot find value `it` in this scope diff --git a/tests/ui/macros/macro-hygiene-help-issue-149604.stderr b/tests/ui/macros/macro-hygiene-help-issue-149604.stderr index dc95cb7a43f00..6df7c009e668b 100644 --- a/tests/ui/macros/macro-hygiene-help-issue-149604.stderr +++ b/tests/ui/macros/macro-hygiene-help-issue-149604.stderr @@ -1,11 +1,11 @@ error[E0425]: cannot find value `it` in this scope - --> $DIR/macro-hygiene-help-issue-149604.rs:7:14 + --> $DIR/macro-hygiene-help-issue-149604.rs:8:14 | LL | let () = it; | ^^ not found in this scope | help: an identifier with the same name is defined here, but is not accessible due to macro hygiene - --> $DIR/macro-hygiene-help-issue-149604.rs:1:35 + --> $DIR/macro-hygiene-help-issue-149604.rs:2:35 | LL | macro_rules! let_it { {} => { let it = (); } } | ^^ @@ -15,7 +15,7 @@ LL | let_it!(); = note: this error originates in the macro `let_it` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0425]: cannot find value `it` in this scope - --> $DIR/macro-hygiene-help-issue-149604.rs:2:50 + --> $DIR/macro-hygiene-help-issue-149604.rs:3:50 | LL | macro_rules! print_it { {} => { println!("{:?}", it); } } | ^^ not found in this scope @@ -24,7 +24,7 @@ LL | print_it!(); | ----------- in this macro invocation | help: an identifier with the same name is defined here, but is not accessible due to macro hygiene - --> $DIR/macro-hygiene-help-issue-149604.rs:1:35 + --> $DIR/macro-hygiene-help-issue-149604.rs:2:35 | LL | macro_rules! let_it { {} => { let it = (); } } | ^^ diff --git a/tests/ui/macros/macro-hygiene-scope-15167.rs b/tests/ui/macros/macro-hygiene-scope-15167.rs index 6578f898a5fb4..ec54f2a7e9887 100644 --- a/tests/ui/macros/macro-hygiene-scope-15167.rs +++ b/tests/ui/macros/macro-hygiene-scope-15167.rs @@ -1,3 +1,4 @@ +//@ reference: macro.decl.hygiene.intro //! Regression test for https://github.com/rust-lang/rust/issues/15167 // macro f should not be able to inject a reference to 'n'. diff --git a/tests/ui/macros/macro-hygiene-scope-15167.stderr b/tests/ui/macros/macro-hygiene-scope-15167.stderr index 332a58467cee1..dbb0514ba1aab 100644 --- a/tests/ui/macros/macro-hygiene-scope-15167.stderr +++ b/tests/ui/macros/macro-hygiene-scope-15167.stderr @@ -1,5 +1,5 @@ error[E0425]: cannot find value `n` in this scope - --> $DIR/macro-hygiene-scope-15167.rs:5:25 + --> $DIR/macro-hygiene-scope-15167.rs:6:25 | LL | macro_rules! f { () => (n) } | ^ not found in this scope @@ -8,14 +8,14 @@ LL | println!("{}", f!()); | ---- in this macro invocation | help: an identifier with the same name exists, but is not accessible due to macro hygiene - --> $DIR/macro-hygiene-scope-15167.rs:12:9 + --> $DIR/macro-hygiene-scope-15167.rs:13:9 | LL | for n in 0..1 { | ^ = note: this error originates in the macro `f` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0425]: cannot find value `n` in this scope - --> $DIR/macro-hygiene-scope-15167.rs:5:25 + --> $DIR/macro-hygiene-scope-15167.rs:6:25 | LL | macro_rules! f { () => (n) } | ^ not found in this scope @@ -24,14 +24,14 @@ LL | println!("{}", f!()); | ---- in this macro invocation | help: an identifier with the same name exists, but is not accessible due to macro hygiene - --> $DIR/macro-hygiene-scope-15167.rs:16:17 + --> $DIR/macro-hygiene-scope-15167.rs:17:17 | LL | if let Some(n) = None { | ^ = note: this error originates in the macro `f` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0425]: cannot find value `n` in this scope - --> $DIR/macro-hygiene-scope-15167.rs:5:25 + --> $DIR/macro-hygiene-scope-15167.rs:6:25 | LL | macro_rules! f { () => (n) } | ^ not found in this scope @@ -40,14 +40,14 @@ LL | println!("{}", f!()); | ---- in this macro invocation | help: an identifier with the same name exists, but is not accessible due to macro hygiene - --> $DIR/macro-hygiene-scope-15167.rs:21:24 + --> $DIR/macro-hygiene-scope-15167.rs:22:24 | LL | } else if let Some(n) = None { | ^ = note: this error originates in the macro `f` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0425]: cannot find value `n` in this scope - --> $DIR/macro-hygiene-scope-15167.rs:5:25 + --> $DIR/macro-hygiene-scope-15167.rs:6:25 | LL | macro_rules! f { () => (n) } | ^ not found in this scope @@ -56,7 +56,7 @@ LL | println!("{}", f!()); | ---- in this macro invocation | help: an identifier with the same name exists, but is not accessible due to macro hygiene - --> $DIR/macro-hygiene-scope-15167.rs:25:20 + --> $DIR/macro-hygiene-scope-15167.rs:26:20 | LL | while let Some(n) = None { | ^ diff --git a/tests/ui/macros/macro-or-patterns-back-compat.fixed b/tests/ui/macros/macro-or-patterns-back-compat.fixed index 5ff249ee17492..0321a36ae3b07 100644 --- a/tests/ui/macros/macro-or-patterns-back-compat.fixed +++ b/tests/ui/macros/macro-or-patterns-back-compat.fixed @@ -1,6 +1,7 @@ //@ edition:2015 //@ run-rustfix //@ aux-build:or-pattern.rs +//@ reference: macro.decl.follow-set.edition2021 #![deny(rust_2021_incompatible_or_patterns)] #![allow(unused_macros)] diff --git a/tests/ui/macros/macro-or-patterns-back-compat.rs b/tests/ui/macros/macro-or-patterns-back-compat.rs index 1c7beaeed7751..5d96ad456dc94 100644 --- a/tests/ui/macros/macro-or-patterns-back-compat.rs +++ b/tests/ui/macros/macro-or-patterns-back-compat.rs @@ -1,6 +1,7 @@ //@ edition:2015 //@ run-rustfix //@ aux-build:or-pattern.rs +//@ reference: macro.decl.follow-set.edition2021 #![deny(rust_2021_incompatible_or_patterns)] #![allow(unused_macros)] diff --git a/tests/ui/macros/macro-or-patterns-back-compat.stderr b/tests/ui/macros/macro-or-patterns-back-compat.stderr index 3718bcb4c8cc4..d4c2c57d0a8bb 100644 --- a/tests/ui/macros/macro-or-patterns-back-compat.stderr +++ b/tests/ui/macros/macro-or-patterns-back-compat.stderr @@ -1,5 +1,5 @@ error: the meaning of the `pat` fragment specifier is changing in Rust 2021, which may affect this macro - --> $DIR/macro-or-patterns-back-compat.rs:11:21 + --> $DIR/macro-or-patterns-back-compat.rs:12:21 | LL | macro_rules! foo { ($x:pat | $y:pat) => {} } | ^^^^^^ help: use pat_param to preserve semantics: `$x:pat_param` @@ -7,13 +7,13 @@ LL | macro_rules! foo { ($x:pat | $y:pat) => {} } = warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2021! = note: for more information, see note: the lint level is defined here - --> $DIR/macro-or-patterns-back-compat.rs:5:9 + --> $DIR/macro-or-patterns-back-compat.rs:6:9 | LL | #![deny(rust_2021_incompatible_or_patterns)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: the meaning of the `pat` fragment specifier is changing in Rust 2021, which may affect this macro - --> $DIR/macro-or-patterns-back-compat.rs:14:23 + --> $DIR/macro-or-patterns-back-compat.rs:15:23 | LL | macro_rules! bar { ($($x:pat)+ | $($y:pat)+) => {} } | ^^^^^^ help: use pat_param to preserve semantics: `$x:pat_param` @@ -22,7 +22,7 @@ LL | macro_rules! bar { ($($x:pat)+ | $($y:pat)+) => {} } = note: for more information, see error: the meaning of the `pat` fragment specifier is changing in Rust 2021, which may affect this macro - --> $DIR/macro-or-patterns-back-compat.rs:20:21 + --> $DIR/macro-or-patterns-back-compat.rs:21:21 | LL | macro_rules! ogg { ($x:pat | $y:pat_param) => {} } | ^^^^^^ help: use pat_param to preserve semantics: `$x:pat_param` @@ -31,7 +31,7 @@ LL | macro_rules! ogg { ($x:pat | $y:pat_param) => {} } = note: for more information, see error: the meaning of the `pat` fragment specifier is changing in Rust 2021, which may affect this macro - --> $DIR/macro-or-patterns-back-compat.rs:24:26 + --> $DIR/macro-or-patterns-back-compat.rs:25:26 | LL | ( $expr:expr , $( $( $pat:pat )|+ => $expr_arm:expr ),+ ) => { | ^^^^^^^^ help: use pat_param to preserve semantics: `$pat:pat_param` diff --git a/tests/ui/macros/macro-pat-follow-2018.rs b/tests/ui/macros/macro-pat-follow-2018.rs index b2a556fce6f9e..37752271c7f0e 100644 --- a/tests/ui/macros/macro-pat-follow-2018.rs +++ b/tests/ui/macros/macro-pat-follow-2018.rs @@ -1,5 +1,6 @@ //@ check-pass //@ edition:2018 +//@ reference: macro.decl.follow-set.edition2021 macro_rules! pat_bar { ($p:pat | $p2:pat) => {{ diff --git a/tests/ui/macros/macro-pat-follow.rs b/tests/ui/macros/macro-pat-follow.rs index 830cc7c0860d1..dfea3e8f7630e 100644 --- a/tests/ui/macros/macro-pat-follow.rs +++ b/tests/ui/macros/macro-pat-follow.rs @@ -1,4 +1,5 @@ //@ run-pass +//@ reference: macro.decl.follow-set.token-pat macro_rules! pat_in { ($p:pat in $e:expr) => {{ let mut iter = $e.into_iter(); diff --git a/tests/ui/macros/macro-pat-pattern-followed-by-or-in-2021.rs b/tests/ui/macros/macro-pat-pattern-followed-by-or-in-2021.rs index 154d6e339a7f9..b300398dd666f 100644 --- a/tests/ui/macros/macro-pat-pattern-followed-by-or-in-2021.rs +++ b/tests/ui/macros/macro-pat-pattern-followed-by-or-in-2021.rs @@ -1,4 +1,5 @@ //@ edition:2021 +//@ reference: macro.decl.follow-set.token-pat #![allow(unused_macros)] macro_rules! foo { ($x:pat | $y:pat) => {} } //~ ERROR `$x:pat` is followed by `|`, which is not allowed for `pat` fragments macro_rules! bar { ($($x:pat)+ | $($y:pat)+) => {} } //~ ERROR `$x:pat` is followed by `|`, which is not allowed for `pat` fragments diff --git a/tests/ui/macros/macro-pat-pattern-followed-by-or-in-2021.stderr b/tests/ui/macros/macro-pat-pattern-followed-by-or-in-2021.stderr index 9179fbc31961c..78500705d2350 100644 --- a/tests/ui/macros/macro-pat-pattern-followed-by-or-in-2021.stderr +++ b/tests/ui/macros/macro-pat-pattern-followed-by-or-in-2021.stderr @@ -1,5 +1,5 @@ error: `$x:pat` is followed by `|`, which is not allowed for `pat` fragments - --> $DIR/macro-pat-pattern-followed-by-or-in-2021.rs:3:28 + --> $DIR/macro-pat-pattern-followed-by-or-in-2021.rs:4:28 | LL | macro_rules! foo { ($x:pat | $y:pat) => {} } | ------ ^ not allowed after `pat` fragments @@ -9,7 +9,7 @@ LL | macro_rules! foo { ($x:pat | $y:pat) => {} } = note: allowed there are: `=>`, `,`, `=`, `if`, `if let` or `in` error: `$x:pat` is followed by `|`, which is not allowed for `pat` fragments - --> $DIR/macro-pat-pattern-followed-by-or-in-2021.rs:4:32 + --> $DIR/macro-pat-pattern-followed-by-or-in-2021.rs:5:32 | LL | macro_rules! bar { ($($x:pat)+ | $($y:pat)+) => {} } | ------ ^ not allowed after `pat` fragments @@ -19,7 +19,7 @@ LL | macro_rules! bar { ($($x:pat)+ | $($y:pat)+) => {} } = note: allowed there are: `=>`, `,`, `=`, `if`, `if let` or `in` error: `$pat:pat` may be followed by `|`, which is not allowed for `pat` fragments - --> $DIR/macro-pat-pattern-followed-by-or-in-2021.rs:7:36 + --> $DIR/macro-pat-pattern-followed-by-or-in-2021.rs:8:36 | LL | ( $expr:expr , $( $( $pat:pat )|+ => $expr_arm:expr ),+ ) => { | -------- ^ not allowed after `pat` fragments diff --git a/tests/ui/macros/macro-pat-pattern-followed-by-or.rs b/tests/ui/macros/macro-pat-pattern-followed-by-or.rs index 59d26a9af2e10..f5a56a7e8edda 100644 --- a/tests/ui/macros/macro-pat-pattern-followed-by-or.rs +++ b/tests/ui/macros/macro-pat-pattern-followed-by-or.rs @@ -1,5 +1,7 @@ //@ edition:2015..2021 //@ run-pass +//@ reference: macro.decl.follow-set.token-pat +//@ reference: macro.decl.follow-set.edition2021 #![allow(unused_macros)] macro_rules! foo { ($x:pat | $y:pat) => {} } // should be ok macro_rules! bar { ($($x:pat)+ | $($y:pat)+) => {} } // should be ok diff --git a/tests/ui/macros/macro-pat2021-pattern-followed-by-or.rs b/tests/ui/macros/macro-pat2021-pattern-followed-by-or.rs index c7dc5d53a9862..a690503a802af 100644 --- a/tests/ui/macros/macro-pat2021-pattern-followed-by-or.rs +++ b/tests/ui/macros/macro-pat2021-pattern-followed-by-or.rs @@ -1,4 +1,6 @@ //@ edition:2021 +//@ reference: macro.decl.follow-set.token-pat +//@ reference: macro.decl.follow-set.edition2021 #![allow(unused_macros)] macro_rules! foo { ($x:pat | $y:pat) => {} } //~ ERROR `$x:pat` is followed by `|`, which is not allowed for `pat` fragments diff --git a/tests/ui/macros/macro-pat2021-pattern-followed-by-or.stderr b/tests/ui/macros/macro-pat2021-pattern-followed-by-or.stderr index af76e3f095f15..2906272af8ad0 100644 --- a/tests/ui/macros/macro-pat2021-pattern-followed-by-or.stderr +++ b/tests/ui/macros/macro-pat2021-pattern-followed-by-or.stderr @@ -1,5 +1,5 @@ error: `$x:pat` is followed by `|`, which is not allowed for `pat` fragments - --> $DIR/macro-pat2021-pattern-followed-by-or.rs:4:28 + --> $DIR/macro-pat2021-pattern-followed-by-or.rs:6:28 | LL | macro_rules! foo { ($x:pat | $y:pat) => {} } | ------ ^ not allowed after `pat` fragments @@ -9,7 +9,7 @@ LL | macro_rules! foo { ($x:pat | $y:pat) => {} } = note: allowed there are: `=>`, `,`, `=`, `if`, `if let` or `in` error: `$x:pat` is followed by `|`, which is not allowed for `pat` fragments - --> $DIR/macro-pat2021-pattern-followed-by-or.rs:7:28 + --> $DIR/macro-pat2021-pattern-followed-by-or.rs:9:28 | LL | macro_rules! ogg { ($x:pat | $y:pat_param) => {} } | ------ ^ not allowed after `pat` fragments @@ -19,7 +19,7 @@ LL | macro_rules! ogg { ($x:pat | $y:pat_param) => {} } = note: allowed there are: `=>`, `,`, `=`, `if`, `if let` or `in` error: `$pat:pat` may be followed by `|`, which is not allowed for `pat` fragments - --> $DIR/macro-pat2021-pattern-followed-by-or.rs:9:35 + --> $DIR/macro-pat2021-pattern-followed-by-or.rs:11:35 | LL | ( $expr:expr , $( $( $pat:pat)|+ => $expr_arm:pat),+ ) => { | -------- ^ not allowed after `pat` fragments diff --git a/tests/ui/macros/macro-rules-as-derive-or-attr-issue-132928.rs b/tests/ui/macros/macro-rules-as-derive-or-attr-issue-132928.rs index a556983e204df..e31c20644fceb 100644 --- a/tests/ui/macros/macro-rules-as-derive-or-attr-issue-132928.rs +++ b/tests/ui/macros/macro-rules-as-derive-or-attr-issue-132928.rs @@ -1,3 +1,4 @@ +//@ reference: names.namespaces.sub-namespaces.intro #![crate_type = "lib"] macro_rules! sample { () => {} } diff --git a/tests/ui/macros/macro-rules-as-derive-or-attr-issue-132928.stderr b/tests/ui/macros/macro-rules-as-derive-or-attr-issue-132928.stderr index a3c21df43e758..43e893ecb3141 100644 --- a/tests/ui/macros/macro-rules-as-derive-or-attr-issue-132928.stderr +++ b/tests/ui/macros/macro-rules-as-derive-or-attr-issue-132928.stderr @@ -1,5 +1,5 @@ error: cannot find attribute `sample` in this scope - --> $DIR/macro-rules-as-derive-or-attr-issue-132928.rs:5:3 + --> $DIR/macro-rules-as-derive-or-attr-issue-132928.rs:6:3 | LL | macro_rules! sample { () => {} } | ------ `sample` exists, but has no `attr` rules @@ -8,7 +8,7 @@ LL | #[sample] | ^^^^^^ error: cannot find derive macro `sample` in this scope - --> $DIR/macro-rules-as-derive-or-attr-issue-132928.rs:6:10 + --> $DIR/macro-rules-as-derive-or-attr-issue-132928.rs:7:10 | LL | macro_rules! sample { () => {} } | ------ `sample` exists, but has no `derive` rules @@ -17,7 +17,7 @@ LL | #[derive(sample)] | ^^^^^^ error: cannot find derive macro `sample` in this scope - --> $DIR/macro-rules-as-derive-or-attr-issue-132928.rs:6:10 + --> $DIR/macro-rules-as-derive-or-attr-issue-132928.rs:7:10 | LL | macro_rules! sample { () => {} } | ------ `sample` exists, but has no `derive` rules diff --git a/tests/ui/macros/macro-shadowing.rs b/tests/ui/macros/macro-shadowing.rs index 710e83dfb3b99..87ed7c8d8fb09 100644 --- a/tests/ui/macros/macro-shadowing.rs +++ b/tests/ui/macros/macro-shadowing.rs @@ -1,4 +1,6 @@ //@ aux-build:two_macros.rs +//@ reference: macro.decl.scope.textual.shadow +//@ reference: names.resolution.expansion.macros.ambiguity.more-expanded-vs-outer #![allow(unused_macros)] diff --git a/tests/ui/macros/macro-shadowing.stderr b/tests/ui/macros/macro-shadowing.stderr index a052b43ac10e4..cf2a57d6319dd 100644 --- a/tests/ui/macros/macro-shadowing.stderr +++ b/tests/ui/macros/macro-shadowing.stderr @@ -1,5 +1,5 @@ error: `macro_two` is already in scope - --> $DIR/macro-shadowing.rs:12:5 + --> $DIR/macro-shadowing.rs:14:5 | LL | #[macro_use] | ^^^^^^^^^^^^ @@ -11,14 +11,14 @@ LL | m1!(); = note: this error originates in the macro `m1` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0659]: `foo` is ambiguous - --> $DIR/macro-shadowing.rs:17:1 + --> $DIR/macro-shadowing.rs:19:1 | LL | foo!(); | ^^^ ambiguous name | = note: ambiguous because of a conflict between a macro-expanded name and a less macro-expanded name from outer scope during import or macro resolution note: `foo` could refer to the macro defined here - --> $DIR/macro-shadowing.rs:10:5 + --> $DIR/macro-shadowing.rs:12:5 | LL | macro_rules! foo { () => {} } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -26,7 +26,7 @@ LL | macro_rules! foo { () => {} } LL | m1!(); | ----- in this macro invocation note: `foo` could also refer to the macro defined here - --> $DIR/macro-shadowing.rs:5:1 + --> $DIR/macro-shadowing.rs:7:1 | LL | macro_rules! foo { () => {} } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/tests/ui/macros/macro-use-all-and-none.rs b/tests/ui/macros/macro-use-all-and-none.rs index 53d450ed8d581..c56a55c4cb193 100644 --- a/tests/ui/macros/macro-use-all-and-none.rs +++ b/tests/ui/macros/macro-use-all-and-none.rs @@ -1,5 +1,6 @@ //@ check-pass //@ aux-build:two_macros-rpass.rs +//@ reference: macro.decl.scope.macro_use.duplicates #![warn(unused_attributes)] diff --git a/tests/ui/macros/macro-use-all-and-none.stderr b/tests/ui/macros/macro-use-all-and-none.stderr index b4c05adcb33d0..0b137ef040958 100644 --- a/tests/ui/macros/macro-use-all-and-none.stderr +++ b/tests/ui/macros/macro-use-all-and-none.stderr @@ -1,12 +1,12 @@ warning: unused attribute - --> $DIR/macro-use-all-and-none.rs:7:12 + --> $DIR/macro-use-all-and-none.rs:8:12 | LL | #[macro_use()] | ^^ help: remove these parentheses | = note: using `macro_use` with an empty list is equivalent to not using a list at all note: the lint level is defined here - --> $DIR/macro-use-all-and-none.rs:4:9 + --> $DIR/macro-use-all-and-none.rs:5:9 | LL | #![warn(unused_attributes)] | ^^^^^^^^^^^^^^^^^ diff --git a/tests/ui/macros/macro-use-bad-args-1.rs b/tests/ui/macros/macro-use-bad-args-1.rs index bfc19981804d0..0f078da44009a 100644 --- a/tests/ui/macros/macro-use-bad-args-1.rs +++ b/tests/ui/macros/macro-use-bad-args-1.rs @@ -1,3 +1,4 @@ +//@ reference: macro.decl.scope.macro_use.syntax #![no_std] #[macro_use(foo(bar))] //~ ERROR malformed `macro_use` attribute input diff --git a/tests/ui/macros/macro-use-bad-args-1.stderr b/tests/ui/macros/macro-use-bad-args-1.stderr index 542b4ae2b7a5e..d1b6b39e4ec17 100644 --- a/tests/ui/macros/macro-use-bad-args-1.stderr +++ b/tests/ui/macros/macro-use-bad-args-1.stderr @@ -1,5 +1,5 @@ error[E0565]: malformed `macro_use` attribute input - --> $DIR/macro-use-bad-args-1.rs:3:1 + --> $DIR/macro-use-bad-args-1.rs:4:1 | LL | #[macro_use(foo(bar))] | ^^^^^^^^^^^^^^^-----^^ diff --git a/tests/ui/macros/macro-use-bad-args-2.rs b/tests/ui/macros/macro-use-bad-args-2.rs index e328b6285d91e..86cb09a66756c 100644 --- a/tests/ui/macros/macro-use-bad-args-2.rs +++ b/tests/ui/macros/macro-use-bad-args-2.rs @@ -1,3 +1,4 @@ +//@ reference: macro.decl.scope.macro_use.syntax #![no_std] #[macro_use(foo="bar")] //~ ERROR malformed `macro_use` attribute input diff --git a/tests/ui/macros/macro-use-bad-args-2.stderr b/tests/ui/macros/macro-use-bad-args-2.stderr index 2db9ffe50b042..f5b577a1ca934 100644 --- a/tests/ui/macros/macro-use-bad-args-2.stderr +++ b/tests/ui/macros/macro-use-bad-args-2.stderr @@ -1,5 +1,5 @@ error[E0565]: malformed `macro_use` attribute input - --> $DIR/macro-use-bad-args-2.rs:3:1 + --> $DIR/macro-use-bad-args-2.rs:4:1 | LL | #[macro_use(foo="bar")] | ^^^^^^^^^^^^^^^------^^ diff --git a/tests/ui/macros/macro-use-both.rs b/tests/ui/macros/macro-use-both.rs index c41797513f6a3..2fdb90dced75b 100644 --- a/tests/ui/macros/macro-use-both.rs +++ b/tests/ui/macros/macro-use-both.rs @@ -1,5 +1,7 @@ //@ check-pass //@ aux-build:two_macros.rs +//@ reference: macro.decl.scope.macro_use.syntax +//@ reference: macro.decl.scope.macro_use.prelude #[macro_use(macro_one, macro_two)] extern crate two_macros; diff --git a/tests/ui/macros/module-macro_use-arguments.rs b/tests/ui/macros/module-macro_use-arguments.rs index 121b492e25437..c459e190d8b99 100644 --- a/tests/ui/macros/module-macro_use-arguments.rs +++ b/tests/ui/macros/module-macro_use-arguments.rs @@ -1,3 +1,4 @@ +//@ reference: macro.decl.scope.macro_use.syntax #[macro_use(foo, bar)] //~ ERROR arguments to `macro_use` are not allowed here mod foo { } diff --git a/tests/ui/macros/module-macro_use-arguments.stderr b/tests/ui/macros/module-macro_use-arguments.stderr index 3ac645ad3a93f..8741103ea8dd4 100644 --- a/tests/ui/macros/module-macro_use-arguments.stderr +++ b/tests/ui/macros/module-macro_use-arguments.stderr @@ -1,5 +1,5 @@ error: arguments to `macro_use` are not allowed here - --> $DIR/module-macro_use-arguments.rs:1:1 + --> $DIR/module-macro_use-arguments.rs:2:1 | LL | #[macro_use(foo, bar)] | ^^^^^^^^^^^^^^^^^^^^^^ From a21eee0396ba56b7089bdfae10683918f7973bbe Mon Sep 17 00:00:00 2001 From: dianqk Date: Wed, 22 Apr 2026 20:30:52 +0800 Subject: [PATCH 133/183] Update LLVM to 22.1.4 --- .gitmodules | 2 +- src/llvm-project | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.gitmodules b/.gitmodules index b11b47ec108bf..c39fabac55f3b 100644 --- a/.gitmodules +++ b/.gitmodules @@ -25,7 +25,7 @@ [submodule "src/llvm-project"] path = src/llvm-project url = https://github.com/rust-lang/llvm-project.git - branch = rustc/22.1-2026-01-27 + branch = rustc/22.1-2026-03-22 shallow = true [submodule "src/doc/embedded-book"] path = src/doc/embedded-book diff --git a/src/llvm-project b/src/llvm-project index 1cb4e3833c191..eaab4d9841b9a 160000 --- a/src/llvm-project +++ b/src/llvm-project @@ -1 +1 @@ -Subproject commit 1cb4e3833c1919c2e6fb579a23ac0e2b22587b7e +Subproject commit eaab4d9841b9a8a12783d927b2df2291c1c79269 From ab1500b8ab123910f65753af89bd9e3d1c60ecc2 Mon Sep 17 00:00:00 2001 From: Yotam Ofek Date: Sat, 29 Nov 2025 14:56:07 +0200 Subject: [PATCH 134/183] Separate out some `IndexItem` fields into a new struct and DRY --- src/librustdoc/formats/cache.rs | 23 +++------ src/librustdoc/html/render/mod.rs | 40 ++++++++++++--- src/librustdoc/html/render/search_index.rs | 58 ++++++++++------------ 3 files changed, 64 insertions(+), 57 deletions(-) diff --git a/src/librustdoc/formats/cache.rs b/src/librustdoc/formats/cache.rs index 35071f47a182b..ebe6a110e9de1 100644 --- a/src/librustdoc/formats/cache.rs +++ b/src/librustdoc/formats/cache.rs @@ -15,9 +15,7 @@ use crate::core::DocContext; use crate::fold::DocFolder; use crate::formats::Impl; use crate::formats::item_type::ItemType; -use crate::html::markdown::short_markdown_summary; -use crate::html::render::IndexItem; -use crate::html::render::search_index::get_function_type_for_search; +use crate::html::render::{IndexItem, IndexItemInfo}; use crate::visit_lib::RustdocEffectiveVisibilities; /// This cache is used to store information about the [`clean::Crate`] being @@ -576,7 +574,6 @@ fn add_item_to_search_index(tcx: TyCtxt<'_>, cache: &mut Cache, item: &clean::It debug_assert!(!item.is_stripped()); - let desc = short_markdown_summary(&item.doc_value(), &item.link_names(cache)); // For searching purposes, a re-export is a duplicate if: // // - It's either an inline, or a true re-export @@ -587,32 +584,24 @@ fn add_item_to_search_index(tcx: TyCtxt<'_>, cache: &mut Cache, item: &clean::It _ => item_def_id, }; let (impl_id, trait_parent) = cache.parent_stack_last_impl_and_trait_id(); - let search_type = get_function_type_for_search( - item, + let info = IndexItemInfo::new( tcx, - clean_impl_generics(cache.parent_stack.last()).as_ref(), - parent_did, cache, + item, + parent_did, + clean_impl_generics(cache.parent_stack.last()).as_ref(), ); - let aliases = item.attrs.get_doc_aliases(); - let is_deprecated = item.is_deprecated(tcx); - let is_unstable = item.is_unstable(); let index_item = IndexItem { - ty: item.type_(), defid: Some(defid), name, module_path: parent_path.to_vec(), - desc, parent: parent_did, parent_idx: None, trait_parent, trait_parent_idx: None, exact_module_path: None, impl_id, - search_type, - aliases, - is_deprecated, - is_unstable, + info, }; cache.search_index.push(index_item); diff --git a/src/librustdoc/html/render/mod.rs b/src/librustdoc/html/render/mod.rs index c0c380447f2cb..8a137434527d1 100644 --- a/src/librustdoc/html/render/mod.rs +++ b/src/librustdoc/html/render/mod.rs @@ -66,7 +66,7 @@ use tracing::{debug, info}; pub(crate) use self::context::*; pub(crate) use self::span_map::{LinkFromSrc, collect_spans_and_sources}; pub(crate) use self::write_shared::*; -use crate::clean::{self, Defaultness, ItemId, RenderedLink}; +use crate::clean::{self, Defaultness, Item, ItemId, RenderedLink}; use crate::display::{Joined as _, MaybeDisplay as _}; use crate::error::Error; use crate::formats::Impl; @@ -79,8 +79,9 @@ use crate::html::format::{ print_type, print_where_clause, visibility_print_with_space, }; use crate::html::markdown::{ - HeadingOffset, IdMap, Markdown, MarkdownItemInfo, MarkdownSummaryLine, + HeadingOffset, IdMap, Markdown, MarkdownItemInfo, MarkdownSummaryLine, short_markdown_summary, }; +use crate::html::render::search_index::get_function_type_for_search; use crate::html::static_files::SCRAPE_EXAMPLES_HELP_MD; use crate::html::{highlight, sources}; use crate::scrape_examples::{CallData, CallLocation}; @@ -124,25 +125,48 @@ enum RenderMode { // Helper structs for rendering items/sidebars and carrying along contextual // information +#[derive(Debug)] +pub(crate) struct IndexItemInfo { + pub(crate) ty: ItemType, + pub(crate) desc: String, + pub(crate) search_type: Option, + pub(crate) aliases: Box<[Symbol]>, + pub(crate) deprecation: Option, + pub(crate) is_unstable: bool, +} + +impl IndexItemInfo { + pub(crate) fn new( + tcx: TyCtxt<'_>, + cache: &Cache, + item: &Item, + parent_did: Option, + impl_generics: Option<&(clean::Type, clean::Generics)>, + ) -> Self { + let ty = item.type_(); + let desc = short_markdown_summary(&item.doc_value(), &item.link_names(cache)); + let search_type = get_function_type_for_search(item, tcx, impl_generics, parent_did, cache); + let aliases = item.attrs.get_doc_aliases(); + let deprecation = item.deprecation(tcx); + let is_unstable = item.is_unstable(); + Self { ty, desc, search_type, aliases, deprecation, is_unstable } + } +} + /// Struct representing one entry in the JS search index. These are all emitted /// by hand to a large JS file at the end of cache-creation. #[derive(Debug)] pub(crate) struct IndexItem { - pub(crate) ty: ItemType, pub(crate) defid: Option, pub(crate) name: Symbol, pub(crate) module_path: Vec, - pub(crate) desc: String, pub(crate) parent: Option, pub(crate) parent_idx: Option, pub(crate) trait_parent: Option, pub(crate) trait_parent_idx: Option, pub(crate) exact_module_path: Option>, pub(crate) impl_id: Option, - pub(crate) search_type: Option, - pub(crate) aliases: Box<[Symbol]>, - pub(crate) is_deprecated: bool, - pub(crate) is_unstable: bool, + pub(crate) info: IndexItemInfo, } /// A type used for the search index. diff --git a/src/librustdoc/html/render/search_index.rs b/src/librustdoc/html/render/search_index.rs index 935fe258c8076..797b103ab9b86 100644 --- a/src/librustdoc/html/render/search_index.rs +++ b/src/librustdoc/html/render/search_index.rs @@ -13,7 +13,7 @@ use ::serde::{Deserialize, Serialize}; use rustc_ast::join_path_syms; use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexMap}; use rustc_data_structures::thin_vec::ThinVec; -use rustc_hir::def_id::LOCAL_CRATE; +use rustc_hir::def_id::{CrateNum, DefIndex, LOCAL_CRATE}; use rustc_hir::find_attr; use rustc_middle::ty::TyCtxt; use rustc_span::def_id::DefId; @@ -29,7 +29,9 @@ use crate::error::Error; use crate::formats::cache::{Cache, OrphanImplItem}; use crate::formats::item_type::ItemType; use crate::html::markdown::short_markdown_summary; -use crate::html::render::{self, IndexItem, IndexItemFunctionType, RenderType, RenderTypeId}; +use crate::html::render::{ + self, IndexItem, IndexItemFunctionType, IndexItemInfo, RenderType, RenderTypeId, +}; #[derive(Clone, Debug, Default, Deserialize, Serialize)] pub(crate) struct SerializedSearchIndex { @@ -1270,29 +1272,18 @@ pub(crate) fn build_index( &cache.orphan_impl_items { if let Some((fqp, _)) = cache.paths.get(&parent) { - let desc = short_markdown_summary(&item.doc_value(), &item.link_names(cache)); + let info = IndexItemInfo::new(tcx, cache, item, Some(parent), impl_generics.as_ref()); search_index.push(IndexItem { - ty: item.type_(), defid: item.item_id.as_def_id(), name: item.name.unwrap(), module_path: fqp[..fqp.len() - 1].to_vec(), - desc, parent: Some(parent), parent_idx: None, trait_parent, trait_parent_idx: None, exact_module_path: None, impl_id, - search_type: get_function_type_for_search( - item, - tcx, - impl_generics.as_ref(), - Some(parent), - cache, - ), - aliases: item.attrs.get_doc_aliases(), - is_deprecated: item.is_deprecated(tcx), - is_unstable: item.is_unstable(), + info, }); } } @@ -1301,11 +1292,10 @@ pub(crate) fn build_index( search_index.sort_unstable_by(|k1, k2| { // `sort_unstable_by_key` produces lifetime errors // HACK(rustdoc): should not be sorting `CrateNum` or `DefIndex`, this will soon go away, too - let k1 = - (&k1.module_path, k1.name.as_str(), &k1.ty, k1.parent.map(|id| (id.index, id.krate))); - let k2 = - (&k2.module_path, k2.name.as_str(), &k2.ty, k2.parent.map(|id| (id.index, id.krate))); - Ord::cmp(&k1, &k2) + fn key(i: &IndexItem) -> (&[Symbol], &str, ItemType, Option<(DefIndex, CrateNum)>) { + (&i.module_path, i.name.as_str(), i.info.ty, i.parent.map(|id| (id.index, id.krate))) + } + Ord::cmp(&key(k1), &key(k2)) }); // Now, convert to an on-disk search index format @@ -1466,7 +1456,7 @@ pub(crate) fn build_index( if fqp.last() != Some(&item.name) { return None; } - let path = if item.ty == ItemType::Macro + let path = if item.info.ty == ItemType::Macro && find_attr!(tcx, defid, MacroExport { .. }) { // `#[macro_export]` always exports to the crate root. @@ -1501,8 +1491,9 @@ pub(crate) fn build_index( if item.impl_id.is_some() && let Some(parent_idx) = item.parent_idx { - let count = - associated_item_duplicates.entry((parent_idx, item.ty, item.name)).or_insert(0); + let count = associated_item_duplicates + .entry((parent_idx, item.info.ty, item.name)) + .or_insert(0); *count += 1; } } @@ -1525,24 +1516,27 @@ pub(crate) fn build_index( let new_entry_id = serialized_index.add_entry( item.name, EntryData { - ty: item.ty, + ty: item.info.ty, parent: item.parent_idx, trait_parent: item.trait_parent_idx, module_path, exact_module_path, - deprecated: item.is_deprecated, - unstable: item.is_unstable, + deprecated: item + .info + .deprecation + .is_some_and(|deprecation| deprecation.is_in_effect()), + unstable: item.info.is_unstable, associated_item_disambiguator_or_extern_crate_url: if let Some(impl_id) = item.impl_id && let Some(parent_idx) = item.parent_idx && associated_item_duplicates - .get(&(parent_idx, item.ty, item.name)) + .get(&(parent_idx, item.info.ty, item.name)) .copied() .unwrap_or(0) > 1 { Some(render::get_id_for_impl(tcx, ItemId::DefId(impl_id))) - } else if item.ty == ItemType::ExternCrate + } else if item.info.ty == ItemType::ExternCrate && let Some(local_def_id) = item.defid.and_then(|def_id| def_id.as_local()) && let cnum = tcx.extern_mod_stmt_cnum(local_def_id).unwrap_or(LOCAL_CRATE) && let Some(ExternalLocation::Remote { url, is_absolute }) = @@ -1555,12 +1549,12 @@ pub(crate) fn build_index( }, krate: crate_idx, }, - item.desc.to_string(), + item.info.desc.to_string(), ); // Aliases // ------- - for alias in &item.aliases[..] { + for alias in &item.info.aliases { serialized_index.push_alias(alias.as_str().to_string(), new_entry_id); } @@ -1833,7 +1827,7 @@ pub(crate) fn build_index( _ => {} } } - if let Some(search_type) = &mut item.search_type { + if let Some(search_type) = &mut item.info.search_type { let mut used_in_function_inputs = BTreeSet::new(); let mut used_in_function_output = BTreeSet::new(); for item in &mut search_type.inputs { @@ -1900,7 +1894,7 @@ pub(crate) fn build_index( // The number 8 is arbitrary. We want it big, but not enormous, // because the postings list has to fill in an empty array for each // unoccupied size. - if item.ty.is_fn_like() { 0 } else { 16 }; + if item.info.ty.is_fn_like() { 0 } else { 16 }; serialized_index.function_data[new_entry_id] = Some(search_type.clone()); #[derive(Clone, Copy)] From ca43552c1377b6fbd79ba7cb03d73814a535feec Mon Sep 17 00:00:00 2001 From: Folkert de Vries Date: Thu, 23 Apr 2026 00:58:43 +0200 Subject: [PATCH 135/183] add the `mem` feature back to `compiler-builtins/Cargo.toml` this was removed by accident before, and only discovered now that we're syncing with the main repo --- library/compiler-builtins/compiler-builtins/Cargo.toml | 1 + 1 file changed, 1 insertion(+) diff --git a/library/compiler-builtins/compiler-builtins/Cargo.toml b/library/compiler-builtins/compiler-builtins/Cargo.toml index aa4e8d2ab2850..b2f1443f2eb09 100644 --- a/library/compiler-builtins/compiler-builtins/Cargo.toml +++ b/library/compiler-builtins/compiler-builtins/Cargo.toml @@ -50,6 +50,7 @@ compiler-builtins = ["dep:core", "unmangled-names"] # Enable `no_mangle` symbols for memory-related intrinsics like memcpy. The # mangled versions are always available. +mem = [] # Enable `no_mangle` symbols so this crate gets used as the runtime intrinsic # implementation. Leave this disabled for testing to avoid conflicting with From 4f7a26f10d0de125063eaebffc609f8e09a8295c Mon Sep 17 00:00:00 2001 From: Lewis McClelland Date: Wed, 22 Apr 2026 23:03:22 -0400 Subject: [PATCH 136/183] Update maintainers of armv7a-vex-v5 --- src/doc/rustc/src/platform-support/armv7a-vex-v5.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/doc/rustc/src/platform-support/armv7a-vex-v5.md b/src/doc/rustc/src/platform-support/armv7a-vex-v5.md index 6b95888b897e0..8c192c6dbdf69 100644 --- a/src/doc/rustc/src/platform-support/armv7a-vex-v5.md +++ b/src/doc/rustc/src/platform-support/armv7a-vex-v5.md @@ -11,7 +11,7 @@ Rust support for this target is not affiliated with VEX Robotics or IFI, and doe This target is maintained by members of the [vexide](https://github.com/vexide) organization: - [@lewisfm](https://github.com/lewisfm) -- [@Tropix126](https://github.com/Tropix126) +- [@tropicaaal](https://github.com/tropicaaal) - [@Gavin-Niederman](https://github.com/Gavin-Niederman) - [@max-niederman](https://github.com/max-niederman) From c0441d42ed38ad5b59a8f62bdda53b89d21949f4 Mon Sep 17 00:00:00 2001 From: teor Date: Fri, 17 Apr 2026 06:45:59 +1000 Subject: [PATCH 137/183] Fix Mlibc env pretty print to Managarm C Library --- src/librustdoc/clean/cfg.rs | 2 +- tests/rustdoc-html/doc-cfg/all-targets.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/librustdoc/clean/cfg.rs b/src/librustdoc/clean/cfg.rs index 631a3b47b5574..2fca37b034a87 100644 --- a/src/librustdoc/clean/cfg.rs +++ b/src/librustdoc/clean/cfg.rs @@ -593,7 +593,7 @@ fn human_readable_target_env(env: Symbol) -> Option<&'static str> { // tidy-alphabetical-start Gnu => "GNU", MacAbi => "Catalyst", - Mlibc => "mac ABI", + Mlibc => "Managarm C Library", Msvc => "MSVC", Musl => "musl", Newlib => "Newlib", diff --git a/tests/rustdoc-html/doc-cfg/all-targets.rs b/tests/rustdoc-html/doc-cfg/all-targets.rs index 048d0d4c73d2b..5b61d6164ee56 100644 --- a/tests/rustdoc-html/doc-cfg/all-targets.rs +++ b/tests/rustdoc-html/doc-cfg/all-targets.rs @@ -2,7 +2,7 @@ //@ has all_targets/fn.foo.html \ // '//*[@id="main-content"]/*[@class="item-info"]/*[@class="stab portability"]' \ -// 'Available on GNU or Catalyst or mac ABI or MSVC or musl or Newlib or \ +// 'Available on GNU or Catalyst or Managarm C Library or MSVC or musl or Newlib or \ // Neutrino 7.0 or Neutrino 7.1 or Neutrino 7.1 with io-sock or Neutrino 8.0 or \ // OpenHarmony or relibc or SGX or Simulator or WASIp1 or WASIp2 or WASIp3 or \ // uClibc or V5 or target_env=fake_env only.' From 140dad0080cfc9968e57b57ef13d106afe91439f Mon Sep 17 00:00:00 2001 From: teor Date: Fri, 17 Apr 2026 07:01:34 +1000 Subject: [PATCH 138/183] Resolve FIXME: os = none is bare metal --- src/librustdoc/clean/cfg.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/librustdoc/clean/cfg.rs b/src/librustdoc/clean/cfg.rs index 2fca37b034a87..ec3407d361ebd 100644 --- a/src/librustdoc/clean/cfg.rs +++ b/src/librustdoc/clean/cfg.rs @@ -516,7 +516,7 @@ fn human_readable_target_os(os: Symbol) -> Option<&'static str> { Managarm => "Managarm", Motor => "Motor OS", NetBsd => "NetBSD", - None => "bare-metal", // FIXME(scrabsha): is this appropriate? + None => "bare-metal", Nto => "QNX Neutrino", NuttX => "NuttX", OpenBsd => "OpenBSD", From 34c0fe87784fdf0ad01aa2cea89e0605c9008818 Mon Sep 17 00:00:00 2001 From: teor Date: Fri, 17 Apr 2026 07:01:53 +1000 Subject: [PATCH 139/183] Fix some typos --- compiler/rustc_target/src/spec/targets/wasm32v1_none.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/rustc_target/src/spec/targets/wasm32v1_none.rs b/compiler/rustc_target/src/spec/targets/wasm32v1_none.rs index 8c5a253b0e2f2..629560af0156f 100644 --- a/compiler/rustc_target/src/spec/targets/wasm32v1_none.rs +++ b/compiler/rustc_target/src/spec/targets/wasm32v1_none.rs @@ -10,7 +10,7 @@ //! those target flags doesn't automatically rebuild libcore / liballoc with //! them, and in order to get those libraries rebuilt you need to use the //! nightly Rust feature `-Zbuild-std`. This target is for people who want to -//! use stable Rust, and target a stable set pf WebAssembly features. +//! use stable Rust, and target a stable set of WebAssembly features. use crate::spec::{Arch, Cc, LinkerFlavor, Os, Target, TargetMetadata, base}; From b15544d52fc005ca0142fb34a40d591147596c8c Mon Sep 17 00:00:00 2001 From: Amanieu d'Antras Date: Thu, 23 Apr 2026 11:17:22 +0100 Subject: [PATCH 140/183] Handle index projections in call destinations in DSE Since call destinations are evaluated after call arguments, we can't turn copy arguments into moves if the same local is later used as an index projection in the call destination. --- .../src/dead_store_elimination.rs | 10 +++++++- ...eadStoreElimination-final.panic-abort.diff | 15 ++++++++++++ ...adStoreElimination-final.panic-unwind.diff | 15 ++++++++++++ .../dead-store-elimination/call_arg_copy.rs | 24 +++++++++++++++++++ 4 files changed, 63 insertions(+), 1 deletion(-) create mode 100644 tests/mir-opt/dead-store-elimination/call_arg_copy.move_index.DeadStoreElimination-final.panic-abort.diff create mode 100644 tests/mir-opt/dead-store-elimination/call_arg_copy.move_index.DeadStoreElimination-final.panic-unwind.diff diff --git a/compiler/rustc_mir_transform/src/dead_store_elimination.rs b/compiler/rustc_mir_transform/src/dead_store_elimination.rs index 63ee69322eef0..e968ed640ecf1 100644 --- a/compiler/rustc_mir_transform/src/dead_store_elimination.rs +++ b/compiler/rustc_mir_transform/src/dead_store_elimination.rs @@ -47,13 +47,21 @@ fn eliminate<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) -> bool { let mut patch = Vec::new(); for (bb, bb_data) in traversal::preorder(body) { - if let TerminatorKind::Call { ref args, .. } = bb_data.terminator().kind { + if let TerminatorKind::Call { ref args, ref destination, .. } = bb_data.terminator().kind { let loc = Location { block: bb, statement_index: bb_data.statements.len() }; // Position ourselves between the evaluation of `args` and the write to `destination`. live.seek_to_block_end(bb); let mut state = live.get().clone(); + // Don't turn into a move if the local is used as an index + // projection for the destination place. + LivenessTransferFunction(&mut state).visit_place( + destination, + visit::PlaceContext::MutatingUse(visit::MutatingUseContext::Call), + loc, + ); + for (index, arg) in args.iter().map(|a| &a.node).enumerate().rev() { if let Operand::Copy(place) = *arg && !place.is_indirect() diff --git a/tests/mir-opt/dead-store-elimination/call_arg_copy.move_index.DeadStoreElimination-final.panic-abort.diff b/tests/mir-opt/dead-store-elimination/call_arg_copy.move_index.DeadStoreElimination-final.panic-abort.diff new file mode 100644 index 0000000000000..012dd7d88a5f0 --- /dev/null +++ b/tests/mir-opt/dead-store-elimination/call_arg_copy.move_index.DeadStoreElimination-final.panic-abort.diff @@ -0,0 +1,15 @@ +- // MIR for `move_index` before DeadStoreElimination-final ++ // MIR for `move_index` after DeadStoreElimination-final + + fn move_index(_1: [usize; 10], _2: usize) -> () { + let mut _0: (); + + bb0: { + _1[_2] = passthrough_usize(copy _2) -> [return: bb1, unwind unreachable]; + } + + bb1: { + return; + } + } + diff --git a/tests/mir-opt/dead-store-elimination/call_arg_copy.move_index.DeadStoreElimination-final.panic-unwind.diff b/tests/mir-opt/dead-store-elimination/call_arg_copy.move_index.DeadStoreElimination-final.panic-unwind.diff new file mode 100644 index 0000000000000..fcd0ae43e2897 --- /dev/null +++ b/tests/mir-opt/dead-store-elimination/call_arg_copy.move_index.DeadStoreElimination-final.panic-unwind.diff @@ -0,0 +1,15 @@ +- // MIR for `move_index` before DeadStoreElimination-final ++ // MIR for `move_index` after DeadStoreElimination-final + + fn move_index(_1: [usize; 10], _2: usize) -> () { + let mut _0: (); + + bb0: { + _1[_2] = passthrough_usize(copy _2) -> [return: bb1, unwind continue]; + } + + bb1: { + return; + } + } + diff --git a/tests/mir-opt/dead-store-elimination/call_arg_copy.rs b/tests/mir-opt/dead-store-elimination/call_arg_copy.rs index 27b5ccdb936db..00a9a49c2abb8 100644 --- a/tests/mir-opt/dead-store-elimination/call_arg_copy.rs +++ b/tests/mir-opt/dead-store-elimination/call_arg_copy.rs @@ -40,7 +40,31 @@ fn move_packed(packed: Packed) { } } +#[inline(never)] +fn passthrough_usize(a: usize) -> usize { + a +} + +// EMIT_MIR call_arg_copy.move_index.DeadStoreElimination-final.diff +#[custom_mir(dialect = "analysis")] +fn move_index(a: [usize; 10], b: usize) { + // CHECK-LABEL: fn move_index( + // CHECK: = passthrough_usize(copy _2) + mir! { + { + // The index is used again after the operand is evaluated to + // evaluate the destionation place, so the argument cannot be turned + // into a move. + Call(a[b] = passthrough_usize(b), ReturnTo(ret), UnwindContinue()) + } + ret = { + Return() + } + } +} + fn main() { move_simple(1); move_packed(Packed { x: 0, y: 1 }); + move_index([0; _], 1); } From ce880a47fd5b544e7b23da2066c3ff35796a4074 Mon Sep 17 00:00:00 2001 From: mejrs <59372212+mejrs@users.noreply.github.com> Date: Thu, 23 Apr 2026 13:40:45 +0200 Subject: [PATCH 141/183] Document `#[diagnostic::on_move]` in the unstable book --- .../language-features/diagnostic-on-move.md | 92 +++++++++++++++++++ 1 file changed, 92 insertions(+) create mode 100644 src/doc/unstable-book/src/language-features/diagnostic-on-move.md diff --git a/src/doc/unstable-book/src/language-features/diagnostic-on-move.md b/src/doc/unstable-book/src/language-features/diagnostic-on-move.md new file mode 100644 index 0000000000000..ba35b07361416 --- /dev/null +++ b/src/doc/unstable-book/src/language-features/diagnostic-on-move.md @@ -0,0 +1,92 @@ +# `diagnostic_on_move` + +The tracking issue for this feature is: [#154181] + +------------------------ + +The `diagnostic_on_move` feature allows use of the `#[diagnostic::on_move]` attribute. It should be +placed on struct, enum and union declarations, though it is not an error to be located in other +positions. This attribute is a hint to the compiler to supplement the error message when the +annotated type is involved in a borrowcheck error. + +For example, [`File`] is annotated as such: +```rust +#![feature(diagnostic_on_move)] + +#[diagnostic::on_move(note = "you can use `File::try_clone` \ + to duplicate a `File` instance")] +pub struct File { + // ... +} +``` + +When you try to use a `File` after it's already been moved, it will helpfully tell you about `try_clone`. + +The message and label can also be customized: + +```rust +#![feature(diagnostic_on_move)] + +use std::marker::PhantomData; + +#[diagnostic::on_move( + message = "`{Self}` cannot be used multiple times", + label = "this token may only be used once", + note = "you can create a new `Token` with `Token::conjure()`" +)] +pub struct Token<'brand> { + spooky: PhantomData<&'brand ()>, +} + +impl Token<'_> { + pub fn conjure<'u>() -> Token<'u> { + Token { + spooky: PhantomData, + } + } +} +``` +The user may try to use it like this: +```rust,compile_fail,E0382 +# #![feature(diagnostic_on_move)] +# +# use std::marker::PhantomData; +# +# #[diagnostic::on_move( +# message = "`{Self}` cannot be used multiple times", +# label = "this token may only be used once", +# note = "you can create a new `Token` with `Token::conjure()`" +# )] +# pub struct Token<'brand> { +# spooky: PhantomData<&'brand ()>, +# } +# +# impl Token<'_> { +# pub fn conjure<'u>() -> Token<'u> { +# Token { +# spooky: PhantomData, +# } +# } +# } +# fn main() { +let token = Token::conjure(); +let _ = (token, token); +# } +``` +This will result in the following error: +```text +error[E0382]: `Token` cannot be used multiple times + --> src/main.rs:24:21 + | + 1 | let token = Token::conjure(); + | ----- this token may only be used once + 2 | let _ = (token, token); + | ----- ^^^^^ value used here after move + | | + | value moved here + | + = note: you can create a new `Token` with `Token::conjure()` +``` + +[`File`]: https://doc.rust-lang.org/nightly/std/fs/struct.File.html "File in std::fs" +[#154181]: https://github.com/rust-lang/rust/issues/154181 "Tracking Issue for #[diagnostic::on_move]" From 2f99ab13f7baf76059b00cdad393126a6cbae2b6 Mon Sep 17 00:00:00 2001 From: "Eddy (Eduard) Stefes" Date: Thu, 23 Apr 2026 13:38:21 +0200 Subject: [PATCH 142/183] Fix classify_union to return Union for regular unions Commit 623c7d7c4bc accidentally changed the return value from REGULAR_UNION to RegularEnum when converting string literals to enum values. Commit b17670d3de2 then renamed RegularUnion to Union, but the buggy return statement remained unchanged. This caused unions to be misclassified as enums, preventing LLDB from displaying union field contents. --- src/etc/rust_types.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/etc/rust_types.py b/src/etc/rust_types.py index 1ed68458ae3a5..ca462654e44e6 100644 --- a/src/etc/rust_types.py +++ b/src/etc/rust_types.py @@ -130,4 +130,4 @@ def classify_union(fields: List) -> RustType: assert len(fields) == 1 return RustType.CompressedEnum else: - return RustType.RegularEnum + return RustType.Union From c1936bad9b6656a59e7bb55b45488e00bdd3b483 Mon Sep 17 00:00:00 2001 From: Walnut <39544927+Walnut356@users.noreply.github.com> Date: Thu, 23 Apr 2026 07:27:44 -0500 Subject: [PATCH 143/183] fix `get_child_at_index` return type hints --- src/etc/lldb_providers.py | 38 +++++++++++++++++++------------------- 1 file changed, 19 insertions(+), 19 deletions(-) diff --git a/src/etc/lldb_providers.py b/src/etc/lldb_providers.py index 407e87cdf785b..d64defe25b8b4 100644 --- a/src/etc/lldb_providers.py +++ b/src/etc/lldb_providers.py @@ -1,6 +1,6 @@ from __future__ import annotations import sys -from typing import Generator, List, TYPE_CHECKING +from typing import Generator, List, TYPE_CHECKING, Optional from lldb import ( SBData, @@ -112,7 +112,7 @@ def get_child_index(self, name: str) -> int: return self.valobj.Dereference().GetSyntheticValue() return self.valobj.GetIndexOfChildWithName(name) - def get_child_at_index(self, index: int) -> SBValue: + def get_child_at_index(self, index: int) -> Optional[SBValue]: return self.valobj.GetChildAtIndex(index) def update(self): @@ -137,7 +137,7 @@ def get_child_index(self, name: str) -> int: return 0 return -1 - def get_child_at_index(self, index: int) -> SBValue: + def get_child_at_index(self, index: int) -> Optional[SBValue]: if index == 0: return self.valobj.Dereference().GetSyntheticValue() return None @@ -164,7 +164,7 @@ def num_children(self) -> int: def get_child_index(self, name: str) -> int: return -1 - def get_child_at_index(self, index: int) -> SBValue: + def get_child_at_index(self, index: int) -> Optional[SBValue]: return None def update(self): @@ -425,7 +425,7 @@ def num_children(self) -> int: def get_child_index(self, name: str) -> int: return self.fields.get(name, -1) - def get_child_at_index(self, index: int) -> SBValue: + def get_child_at_index(self, index: int) -> Optional[SBValue]: if self.is_variant: field = self.type.GetFieldAtIndex(index + 1) else: @@ -470,7 +470,7 @@ def get_child_index(self, name: str) -> int: return -1 - def get_child_at_index(self, index: int) -> SBValue: + def get_child_at_index(self, index: int) -> Optional[SBValue]: if not 0 <= index < self.length: return None start = self.data_ptr.GetValueAsUnsigned() @@ -506,7 +506,7 @@ def get_child_index(self, name: str) -> int: return -1 - def get_child_at_index(self, index: int) -> SBValue: + def get_child_at_index(self, index: int) -> Optional[SBValue]: if not 0 <= index < self.length: return None start = self.data_ptr.GetValueAsUnsigned() @@ -562,7 +562,7 @@ def num_children(self) -> int: def get_child_index(self, name: str) -> int: return self.value.GetIndexOfChildWithName(name) - def get_child_at_index(self, index: int) -> SBValue: + def get_child_at_index(self, index: int) -> Optional[SBValue]: return self.value.GetChildAtIndex(index) def update(self): @@ -768,7 +768,7 @@ def num_children(self) -> int: def get_child_index(self, name: str) -> int: return self.value.GetIndexOfChildWithName(name) - def get_child_at_index(self, index: int) -> SBValue: + def get_child_at_index(self, index: int) -> Optional[SBValue]: return self.value.GetChildAtIndex(index) def has_children(self) -> bool: @@ -858,7 +858,7 @@ def get_child_index(self, name: str) -> int: else: return -1 - def get_child_at_index(self, index: int) -> SBValue: + def get_child_at_index(self, index: int) -> Optional[SBValue]: if self.is_variant: field = self.type.GetFieldAtIndex(index + 1) else: @@ -887,7 +887,7 @@ def num_children(self) -> int: def get_child_index(self, name: str) -> int: return self.valobj.GetIndexOfChildWithName(name) - def get_child_at_index(self, index: int) -> SBValue: + def get_child_at_index(self, index: int) -> Optional[SBValue]: child: SBValue = self.valobj.GetChildAtIndex(index) offset = self.valobj.GetType().GetFieldAtIndex(index).byte_offset return self.valobj.CreateChildAtOffset(str(index), offset, child.GetType()) @@ -935,7 +935,7 @@ def get_child_index(self, name: str) -> int: else: return -1 - def get_child_at_index(self, index: int) -> SBValue: + def get_child_at_index(self, index: int) -> Optional[SBValue]: start = self.data_ptr.GetValueAsUnsigned() address = start + index * self.element_type_size element = self.data_ptr.CreateValueFromAddress( @@ -983,7 +983,7 @@ def get_child_index(self, name: str) -> int: else: return -1 - def get_child_at_index(self, index: int) -> SBValue: + def get_child_at_index(self, index: int) -> Optional[SBValue]: start = self.data_ptr.GetValueAsUnsigned() address = start + index * self.element_size element = self.data_ptr.CreateValueFromAddress( @@ -1047,7 +1047,7 @@ def get_child_index(self, name: str) -> int: else: return -1 - def get_child_at_index(self, index: int) -> SBValue: + def get_child_at_index(self, index: int) -> Optional[SBValue]: start = self.data_ptr.GetValueAsUnsigned() address = start + ((index + self.head) % self.cap) * self.element_type_size element = self.data_ptr.CreateValueFromAddress( @@ -1106,7 +1106,7 @@ def get_child_index(self, name: str) -> int: else: return -1 - def get_child_at_index(self, index: int) -> SBValue: + def get_child_at_index(self, index: int) -> Optional[SBValue]: # logger = Logger.Logger() start = self.data_ptr.GetValueAsUnsigned() & ~1 @@ -1195,7 +1195,7 @@ def get_child_index(self, name: str) -> int: else: return -1 - def get_child_at_index(self, index: int) -> SBValue: + def get_child_at_index(self, index: int) -> Optional[SBValue]: pairs_start = self.data_ptr.GetValueAsUnsigned() idx = self.valid_indices[index] if self.new_layout: @@ -1318,7 +1318,7 @@ def get_child_index(self, name: str) -> int: return 2 return -1 - def get_child_at_index(self, index: int) -> SBValue: + def get_child_at_index(self, index: int) -> Optional[SBValue]: if index == 0: return self.value if index == 1: @@ -1351,7 +1351,7 @@ def get_child_index(self, name: str) -> int: return 0 return -1 - def get_child_at_index(self, index: int) -> SBValue: + def get_child_at_index(self, index: int) -> Optional[SBValue]: if index == 0: return self.value return None @@ -1406,7 +1406,7 @@ def get_child_index(self, name: str) -> int: return 1 return -1 - def get_child_at_index(self, index: int) -> SBValue: + def get_child_at_index(self, index: int) -> Optional[SBValue]: if index == 0: return self.value if index == 1: From b86c9e77e0e35f9e84951267719b13cf7f2b91d9 Mon Sep 17 00:00:00 2001 From: Walnut <39544927+Walnut356@users.noreply.github.com> Date: Thu, 23 Apr 2026 07:32:33 -0500 Subject: [PATCH 144/183] fix array template arg lookup behavior --- src/etc/lldb_providers.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/etc/lldb_providers.py b/src/etc/lldb_providers.py index 407e87cdf785b..be27fbdde62ae 100644 --- a/src/etc/lldb_providers.py +++ b/src/etc/lldb_providers.py @@ -233,8 +233,6 @@ def resolve_msvc_template_arg(arg_name: str, target: SBTarget) -> SBType: return result.GetPointerType() if arg_name.startswith("array$<"): - arg_name = arg_name[7:-1].strip() - template_args = get_template_args(arg_name) element_name = next(template_args) From 797059769ebfee93e563db4a3130eb56c37ac69b Mon Sep 17 00:00:00 2001 From: Folkert de Vries Date: Wed, 22 Apr 2026 22:37:16 +0200 Subject: [PATCH 145/183] c-variadic: fix for sparc64 validated versus https://godbolt.org/z/qrM37rY6n --- compiler/rustc_codegen_llvm/src/va_arg.rs | 22 +++- .../{c-variadic-arm.rs => c-variadic/arm.rs} | 4 +- .../mips.rs} | 0 tests/assembly-llvm/c-variadic/sparc.rs | 112 ++++++++++++++++++ 4 files changed, 136 insertions(+), 2 deletions(-) rename tests/assembly-llvm/{c-variadic-arm.rs => c-variadic/arm.rs} (73%) rename tests/assembly-llvm/{c-variadic-mips.rs => c-variadic/mips.rs} (100%) create mode 100644 tests/assembly-llvm/c-variadic/sparc.rs diff --git a/compiler/rustc_codegen_llvm/src/va_arg.rs b/compiler/rustc_codegen_llvm/src/va_arg.rs index 3cd4e490fd5ba..cfdd47b3a8c8c 100644 --- a/compiler/rustc_codegen_llvm/src/va_arg.rs +++ b/compiler/rustc_codegen_llvm/src/va_arg.rs @@ -88,11 +88,30 @@ enum SlotSize { Bytes1 = 1, } +/// Whether to respect a value alignment that is higher than the slot alignment. +/// +/// When `No` the argument is in the next slot, when `Yes` there will be empty slots +/// until a slot's starting address has the required alignment. enum AllowHigherAlign { No, Yes, } +/// Determines where in the slot the value is located. Only takes effect on big-endian targets. +/// +/// with 8-byte slots, a 32-bit integer is either stored right-adjusted: +/// +/// ```text +/// [0x0, 0x0, 0x0, 0x0, 0xaa, 0xaa, 0xaa, 0xaa] +/// ``` +/// +/// or left-adjusted: +/// +/// ```text +/// [0xaa, 0xaa, 0xaa, 0xaa, 0x0, 0x0, 0x0, 0x0] +/// ``` +/// +/// Most big-endian targets store values as right-adjusted. enum ForceRightAdjust { No, Yes, @@ -1169,7 +1188,8 @@ pub(super) fn emit_va_arg<'ll, 'tcx>( if target_ty_size > 2 * 8 { PassMode::Indirect } else { PassMode::Direct }, SlotSize::Bytes8, AllowHigherAlign::Yes, - ForceRightAdjust::No, + // sparc64 is a big-endian target and stores variable arguments right-adjusted. + ForceRightAdjust::Yes, ), Arch::Mips | Arch::Mips32r6 | Arch::Mips64 | Arch::Mips64r6 => emit_ptr_va_arg( bx, diff --git a/tests/assembly-llvm/c-variadic-arm.rs b/tests/assembly-llvm/c-variadic/arm.rs similarity index 73% rename from tests/assembly-llvm/c-variadic-arm.rs rename to tests/assembly-llvm/c-variadic/arm.rs index 1cfc115badeed..682e9736958b1 100644 --- a/tests/assembly-llvm/c-variadic-arm.rs +++ b/tests/assembly-llvm/c-variadic/arm.rs @@ -7,7 +7,9 @@ #![crate_type = "lib"] #![feature(c_variadic)] -// Check that the assembly that rustc generates matches what clang emits. +// Check that the assembly that rustc generates matches what clang emits. This example in particular +// is related to https://github.com/rust-lang/rust/pull/144549 and shows the effect of us correctly +// emitting annotations that start and end the lifetime of the va_list. #[unsafe(no_mangle)] unsafe extern "C" fn variadic(a: f64, mut args: ...) -> f64 { diff --git a/tests/assembly-llvm/c-variadic-mips.rs b/tests/assembly-llvm/c-variadic/mips.rs similarity index 100% rename from tests/assembly-llvm/c-variadic-mips.rs rename to tests/assembly-llvm/c-variadic/mips.rs diff --git a/tests/assembly-llvm/c-variadic/sparc.rs b/tests/assembly-llvm/c-variadic/sparc.rs new file mode 100644 index 0000000000000..59f039e7df28b --- /dev/null +++ b/tests/assembly-llvm/c-variadic/sparc.rs @@ -0,0 +1,112 @@ +//@ add-minicore +//@ assembly-output: emit-asm +// +//@ revisions: SPARC SPARC64 +//@ [SPARC] compile-flags: -Copt-level=3 --target sparc-unknown-linux-gnu +//@ [SPARC] needs-llvm-components: sparc +//@ [SPARC64] compile-flags: -Copt-level=3 --target sparc64-unknown-linux-gnu +//@ [SPARC64] needs-llvm-components: sparc +#![feature(c_variadic, no_core, lang_items, intrinsics, rustc_attrs, asm_experimental_arch)] +#![no_core] +#![crate_type = "lib"] + +// Check that the assembly that rustc generates matches what clang emits. + +extern crate minicore; +use minicore::*; + +#[lang = "va_arg_safe"] +pub unsafe trait VaArgSafe {} + +unsafe impl VaArgSafe for i32 {} +unsafe impl VaArgSafe for i64 {} +unsafe impl VaArgSafe for f64 {} +unsafe impl VaArgSafe for *const T {} + +#[repr(transparent)] +struct VaListInner { + ptr: *const c_void, +} + +#[repr(transparent)] +#[lang = "va_list"] +pub struct VaList<'a> { + inner: VaListInner, + _marker: PhantomData<&'a mut ()>, +} + +#[rustc_intrinsic] +#[rustc_nounwind] +pub const unsafe fn va_arg(ap: &mut VaList<'_>) -> T; + +#[unsafe(no_mangle)] +unsafe extern "C" fn read_f64(ap: &mut VaList<'_>) -> f64 { + // CHECK-LABEL: read_f64 + // + // SPARC: ld [%o0], %o1 + // SPARC-NEXT: add %o1, 8, %o2 + // SPARC-NEXT: st %o2, [%o0] + // SPARC-NEXT: ld [%o1+4], %o0 + // SPARC-NEXT: add %sp, 96, %o2 + // SPARC-NEXT: or %o2, 4, %o2 + // SPARC-NEXT: st %o0, [%o2] + // SPARC-NEXT: ld [%o1], %o0 + // SPARC-NEXT: st %o0, [%sp+96] + // SPARC-NEXT: ldd [%sp+96], %f0 + // SPARC-NEXT: retl + // SPARC-NEXT: add %sp, 104, %sp + // + // SPARC64: ldx [%o0], %o1 + // SPARC64-NEXT: add %o1, 8, %o2 + // SPARC64-NEXT: stx %o2, [%o0] + // SPARC64-NEXT: retl + // SPARC64-NEXT: ldd [%o1], %f0 + va_arg(ap) +} + +#[unsafe(no_mangle)] +unsafe extern "C" fn read_i32(ap: &mut VaList<'_>) -> i32 { + // CHECK-LABEL: read_i32 + // + // SPARC: ld [%o0], %o1 + // SPARC-NEXT: add %o1, 4, %o2 + // SPARC-NEXT: st %o2, [%o0] + // SPARC-NEXT: retl + // SPARC-NEXT: ld [%o1], %o0 + // + // SPARC64: ldx [%o0], %o1 + // SPARC64-NEXT: add %o1, 8, %o2 + // SPARC64-NEXT: stx %o2, [%o0] + // SPARC64-NEXT: retl + // SPARC64-NEXT: ldsw [%o1+4], %o0 + va_arg(ap) +} + +#[unsafe(no_mangle)] +unsafe extern "C" fn read_i64(ap: &mut VaList<'_>) -> i64 { + // CHECK-LABEL: read_i64 + // + // SPARC: ld [%o0], %o1 + // SPARC-NEXT: add %o1, 4, %o2 + // SPARC-NEXT: st %o2, [%o0] + // SPARC-NEXT: ld [%o1], %o2 + // SPARC-NEXT: add %o1, 8, %o3 + // SPARC-NEXT: st %o3, [%o0] + // SPARC-NEXT: ld [%o1+4], %o1 + // SPARC-NEXT: retl + // SPARC-NEXT: mov %o2, %o0 + // + // SPARC64: ldx [%o0], %o1 + // SPARC64-NEXT: add %o1, 8, %o2 + // SPARC64-NEXT: stx %o2, [%o0] + // SPARC64-NEXT: retl + // SPARC64-NEXT: ldx [%o1], %o0 + va_arg(ap) +} + +#[unsafe(no_mangle)] +unsafe extern "C" fn read_ptr(ap: &mut VaList<'_>) -> *const u8 { + // SPARC: read_ptr = read_i32 + // SPARC64: read_ptr = read_i64 + va_arg(ap) +} From 892f176d899dd218285d82489603fa700a1ed6f6 Mon Sep 17 00:00:00 2001 From: Daria Sukhonina Date: Thu, 23 Apr 2026 16:06:24 +0300 Subject: [PATCH 146/183] Const initialize `LOCK_LATCH` thread local --- compiler/rustc_thread_pool/src/latch.rs | 2 +- compiler/rustc_thread_pool/src/registry.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/compiler/rustc_thread_pool/src/latch.rs b/compiler/rustc_thread_pool/src/latch.rs index 29c85146e4f17..da3937a5ff415 100644 --- a/compiler/rustc_thread_pool/src/latch.rs +++ b/compiler/rustc_thread_pool/src/latch.rs @@ -220,7 +220,7 @@ pub(super) struct LockLatch { impl LockLatch { #[inline] - pub(super) fn new() -> LockLatch { + pub(super) const fn new() -> LockLatch { LockLatch { m: Mutex::new(false), v: Condvar::new() } } diff --git a/compiler/rustc_thread_pool/src/registry.rs b/compiler/rustc_thread_pool/src/registry.rs index 92bb8961e7dfc..9510c1842f86a 100644 --- a/compiler/rustc_thread_pool/src/registry.rs +++ b/compiler/rustc_thread_pool/src/registry.rs @@ -524,7 +524,7 @@ impl Registry { OP: FnOnce(&WorkerThread, bool) -> R + Send, R: Send, { - thread_local!(static LOCK_LATCH: LockLatch = LockLatch::new()); + thread_local!(static LOCK_LATCH: LockLatch = const { LockLatch::new() }); LOCK_LATCH.with(|l| { // This thread isn't a member of *any* thread pool, so just block. From 714df2bf0040146225a80dda231e03b99cf3a61e Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Mon, 13 Apr 2026 16:44:21 +0300 Subject: [PATCH 147/183] privacy: Assert that compared visibilities are (usually) ordered Also use `greater_than` instead of `is_at_least` for comparing visibilities, which we can do because visibilities are asserted to be ordered now. --- .../src/coherence/builtin.rs | 2 +- compiler/rustc_middle/src/middle/privacy.rs | 30 ++++++++----- compiler/rustc_middle/src/ty/mod.rs | 45 +++++++++++++++---- compiler/rustc_privacy/src/lib.rs | 6 +-- .../rustc_resolve/src/build_reduced_graph.rs | 2 +- compiler/rustc_resolve/src/imports.rs | 36 +++++++-------- 6 files changed, 77 insertions(+), 44 deletions(-) diff --git a/compiler/rustc_hir_analysis/src/coherence/builtin.rs b/compiler/rustc_hir_analysis/src/coherence/builtin.rs index d1ce29b703eea..7c3511e91d79d 100644 --- a/compiler/rustc_hir_analysis/src/coherence/builtin.rs +++ b/compiler/rustc_hir_analysis/src/coherence/builtin.rs @@ -190,7 +190,7 @@ fn visit_implementation_of_const_param_ty(checker: &Checker<'_>) -> Result<(), E let struct_vis = tcx.visibility(adt.did()); for variant in adt.variants() { for field in &variant.fields { - if !field.vis.is_at_least(struct_vis, tcx) { + if struct_vis.greater_than(field.vis, tcx) { let span = tcx.hir_expect_item(impl_did).expect_impl().self_ty.span; return Err(tcx .dcx() diff --git a/compiler/rustc_middle/src/middle/privacy.rs b/compiler/rustc_middle/src/middle/privacy.rs index 0be4c8243d632..c24e433073cce 100644 --- a/compiler/rustc_middle/src/middle/privacy.rs +++ b/compiler/rustc_middle/src/middle/privacy.rs @@ -2,6 +2,7 @@ //! outside their scopes. This pass will also generate a set of exported items //! which are available for use externally when compiled as a library. +use std::cmp::Ordering; use std::hash::Hash; use rustc_data_structures::fx::{FxIndexMap, IndexEntry}; @@ -82,7 +83,9 @@ impl EffectiveVisibility { for l in Level::all_levels() { let rhs_vis = self.at_level_mut(l); let lhs_vis = *lhs.at_level(l); - if rhs_vis.is_at_least(lhs_vis, tcx) { + // FIXME: figure out why unordered visibilities occur here, + // and what the behavior for them should be. + if rhs_vis.partial_cmp(lhs_vis, tcx) == Some(Ordering::Greater) { *rhs_vis = lhs_vis; }; } @@ -139,9 +142,7 @@ impl EffectiveVisibilities { for l in Level::all_levels() { let vis_at_level = eff_vis.at_level(l); let old_vis_at_level = old_eff_vis.at_level_mut(l); - if vis_at_level != old_vis_at_level - && vis_at_level.is_at_least(*old_vis_at_level, tcx) - { + if vis_at_level.greater_than(*old_vis_at_level, tcx) { *old_vis_at_level = *vis_at_level } } @@ -160,16 +161,16 @@ impl EffectiveVisibilities { // and all effective visibilities are larger or equal than private visibility. let private_vis = Visibility::Restricted(tcx.parent_module_from_def_id(def_id)); let span = tcx.def_span(def_id.to_def_id()); - if !ev.direct.is_at_least(private_vis, tcx) { + if private_vis.greater_than(ev.direct, tcx) { span_bug!(span, "private {:?} > direct {:?}", private_vis, ev.direct); } - if !ev.reexported.is_at_least(ev.direct, tcx) { + if ev.direct.greater_than(ev.reexported, tcx) { span_bug!(span, "direct {:?} > reexported {:?}", ev.direct, ev.reexported); } - if !ev.reachable.is_at_least(ev.reexported, tcx) { + if ev.reexported.greater_than(ev.reachable, tcx) { span_bug!(span, "reexported {:?} > reachable {:?}", ev.reexported, ev.reachable); } - if !ev.reachable_through_impl_trait.is_at_least(ev.reachable, tcx) { + if ev.reachable.greater_than(ev.reachable_through_impl_trait, tcx) { span_bug!( span, "reachable {:?} > reachable_through_impl_trait {:?}", @@ -183,7 +184,7 @@ impl EffectiveVisibilities { let is_impl = matches!(tcx.def_kind(def_id), DefKind::Impl { .. }); if !is_impl && tcx.trait_impl_of_assoc(def_id.to_def_id()).is_none() { let nominal_vis = tcx.visibility(def_id); - if !nominal_vis.is_at_least(ev.reachable, tcx) { + if ev.reachable.greater_than(nominal_vis, tcx) { span_bug!( span, "{:?}: reachable {:?} > nominal {:?}", @@ -242,8 +243,11 @@ impl EffectiveVisibilities { if !(inherited_effective_vis_at_prev_level == inherited_effective_vis_at_level && level != l) { + // FIXME: figure out why unordered visibilities occur here, + // and what the behavior for them should be. calculated_effective_vis = if let Some(max_vis) = max_vis - && !max_vis.is_at_least(inherited_effective_vis_at_level, tcx) + && inherited_effective_vis_at_level.partial_cmp(max_vis, tcx) + == Some(Ordering::Greater) { max_vis } else { @@ -252,8 +256,10 @@ impl EffectiveVisibilities { } // effective visibility can't be decreased at next update call for the // same id - if *current_effective_vis_at_level != calculated_effective_vis - && calculated_effective_vis.is_at_least(*current_effective_vis_at_level, tcx) + // FIXME: figure out why unordered visibilities occur here, + // and what the behavior for them should be. + if calculated_effective_vis.partial_cmp(*current_effective_vis_at_level, tcx) + == Some(Ordering::Greater) { changed = true; *current_effective_vis_at_level = calculated_effective_vis; diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs index 59cc6a601bfa8..1ec2695710073 100644 --- a/compiler/rustc_middle/src/ty/mod.rs +++ b/compiler/rustc_middle/src/ty/mod.rs @@ -11,6 +11,7 @@ #![allow(rustc::usage_of_ty_tykind)] +use std::cmp::Ordering; use std::fmt::Debug; use std::hash::{Hash, Hasher}; use std::marker::PhantomData; @@ -379,18 +380,46 @@ impl> Visibility { } } - /// Returns `true` if this visibility is at least as accessible as the given visibility - pub fn is_at_least(self, vis: Visibility>, tcx: TyCtxt<'_>) -> bool { - match vis { - Visibility::Public => self.is_public(), - Visibility::Restricted(id) => self.is_accessible_from(id, tcx), + pub fn partial_cmp( + self, + vis: Visibility>, + tcx: TyCtxt<'_>, + ) -> Option { + match (self, vis) { + (Visibility::Public, Visibility::Public) => Some(Ordering::Equal), + (Visibility::Public, Visibility::Restricted(_)) => Some(Ordering::Greater), + (Visibility::Restricted(_), Visibility::Public) => Some(Ordering::Less), + (Visibility::Restricted(lhs_id), Visibility::Restricted(rhs_id)) => { + let (lhs_id, rhs_id) = (lhs_id.into(), rhs_id.into()); + if lhs_id == rhs_id { + Some(Ordering::Equal) + } else if tcx.is_descendant_of(rhs_id, lhs_id) { + Some(Ordering::Greater) + } else if tcx.is_descendant_of(lhs_id, rhs_id) { + Some(Ordering::Less) + } else { + None + } + } } } } -impl + Copy> Visibility { - pub fn min(self, vis: Visibility, tcx: TyCtxt<'_>) -> Visibility { - if self.is_at_least(vis, tcx) { vis } else { self } +impl + Debug + Copy> Visibility { + /// Returns `true` if this visibility is strictly larger than the given visibility. + #[track_caller] + pub fn greater_than( + self, + vis: Visibility + Debug + Copy>, + tcx: TyCtxt<'_>, + ) -> bool { + match self.partial_cmp(vis, tcx) { + Some(ord) => ord.is_gt(), + None => { + tcx.dcx().delayed_bug(format!("unordered visibilities: {self:?} and {vis:?}")); + false + } + } } } diff --git a/compiler/rustc_privacy/src/lib.rs b/compiler/rustc_privacy/src/lib.rs index 58121b8123c35..ba30dfccc33cc 100644 --- a/compiler/rustc_privacy/src/lib.rs +++ b/compiler/rustc_privacy/src/lib.rs @@ -337,7 +337,7 @@ fn assoc_has_type_of(tcx: TyCtxt<'_>, item: &ty::AssocItem) -> bool { } fn min(vis1: ty::Visibility, vis2: ty::Visibility, tcx: TyCtxt<'_>) -> ty::Visibility { - if vis1.is_at_least(vis2, tcx) { vis2 } else { vis1 } + if vis1.greater_than(vis2, tcx) { vis2 } else { vis1 } } /// Visitor used to determine impl visibility and reachability. @@ -1465,7 +1465,7 @@ impl SearchInterfaceForPrivateItemsVisitor<'_> { }; let vis = self.tcx.local_visibility(local_def_id); - if self.hard_error && !vis.is_at_least(self.required_visibility, self.tcx) { + if self.hard_error && self.required_visibility.greater_than(vis, self.tcx) { let vis_descr = match vis { ty::Visibility::Public => "public", ty::Visibility::Restricted(vis_def_id) => { @@ -1499,7 +1499,7 @@ impl SearchInterfaceForPrivateItemsVisitor<'_> { let reachable_at_vis = *effective_vis.at_level(Level::Reachable); - if !vis.is_at_least(reachable_at_vis, self.tcx) { + if reachable_at_vis.greater_than(vis, self.tcx) { let lint = if self.in_primary_interface { lint::builtin::PRIVATE_INTERFACES } else { diff --git a/compiler/rustc_resolve/src/build_reduced_graph.rs b/compiler/rustc_resolve/src/build_reduced_graph.rs index 7482bd3283c8c..cf234080e100a 100644 --- a/compiler/rustc_resolve/src/build_reduced_graph.rs +++ b/compiler/rustc_resolve/src/build_reduced_graph.rs @@ -924,7 +924,7 @@ impl<'a, 'ra, 'tcx> DefCollector<'a, 'ra, 'tcx> { let field_vis = self .try_resolve_visibility(&field.vis, false) .unwrap_or(Visibility::Public); - if ctor_vis.is_at_least(field_vis, self.r.tcx) { + if ctor_vis.greater_than(field_vis, self.r.tcx) { ctor_vis = field_vis; } field_visibilities.push(field_vis.to_def_id()); diff --git a/compiler/rustc_resolve/src/imports.rs b/compiler/rustc_resolve/src/imports.rs index 4cb9a653e010a..2aaab33283d39 100644 --- a/compiler/rustc_resolve/src/imports.rs +++ b/compiler/rustc_resolve/src/imports.rs @@ -1,5 +1,6 @@ //! A bunch of methods and structures more or less related to resolving imports. +use std::cmp::Ordering; use std::mem; use rustc_ast::{Item, NodeId}; @@ -373,24 +374,21 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { pub(crate) fn import_decl_vis(&self, decl: Decl<'ra>, import: ImportSummary) -> Visibility { assert!(import.vis.is_accessible_from(import.nearest_parent_mod, self.tcx)); let decl_vis = decl.vis(); - if decl_vis.is_at_least(import.vis, self.tcx) { - // Ordered, import is less visible than the imported declaration, or the same, - // use the import's visibility. - import.vis - } else if decl_vis.is_accessible_from(import.nearest_parent_mod, self.tcx) { - // Ordered, imported declaration is less visible than the import, but is still visible + if decl_vis.partial_cmp(import.vis, self.tcx) == Some(Ordering::Less) + && decl_vis.is_accessible_from(import.nearest_parent_mod, self.tcx) + && pub_use_of_private_extern_crate_hack(import, decl).is_none() + { + // Imported declaration is less visible than the import, but is still visible // from the current module, use the declaration's visibility. - assert!(import.vis.is_at_least(decl_vis, self.tcx)); - if pub_use_of_private_extern_crate_hack(import, decl).is_some() { - import.vis - } else { - decl_vis.expect_local() - } + decl_vis.expect_local() } else { - // Ordered or not, the imported declaration is too private for the current module. + // Good case - imported declaration is more visible than the import, or the same, + // use the import's visibility. + // Bad case - imported declaration is too private for the current module. // It doesn't matter what visibility we choose here (except in the `PRIVATE_MACRO_USE` - // case), because either some error will be reported, or the import declaration - // will be thrown away (unfortunately cannot use delayed bug here for this reason). + // and `PUB_USE_OF_PRIVATE_EXTERN_CRATE` cases), because either some error will be + // reported, or the import declaration will be thrown away (unfortunately cannot use + // delayed bug here for this reason). // Use import visibility to keep the all declaration visibilities in a module ordered. import.vis } @@ -403,7 +401,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { if let ImportKind::Glob { ref max_vis, .. } = import.kind && (vis == import.vis - || max_vis.get().is_none_or(|max_vis| vis.is_at_least(max_vis, self.tcx))) + || max_vis.get().is_none_or(|max_vis| vis.greater_than(max_vis, self.tcx))) { max_vis.set_unchecked(Some(vis)) } @@ -474,7 +472,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { // FIXME: remove this when `warn_ambiguity` is removed (#149195). self.arenas.alloc_decl((*old_glob_decl).clone()) } - } else if !old_glob_decl.vis().is_at_least(glob_decl.vis(), self.tcx) { + } else if glob_decl.vis().greater_than(old_glob_decl.vis(), self.tcx) { // We are glob-importing the same item but with greater visibility. // All visibilities here are ordered because all of them are ancestors of `module`. // FIXME: Update visibility in place, but without regressions @@ -1244,7 +1242,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { }); } if let Some(max_vis) = max_vis.get() - && !max_vis.is_at_least(import.vis, self.tcx) + && import.vis.greater_than(max_vis, self.tcx) { let def_id = self.local_def_id(id); self.lint_buffer.buffer_lint( @@ -1493,7 +1491,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { return; }; - if !binding.vis().is_at_least(import.vis, this.tcx) { + if import.vis.greater_than(binding.vis(), this.tcx) { reexport_error = Some((ns, binding)); if let Visibility::Restricted(binding_def_id) = binding.vis() && binding_def_id.is_top_level_module() From 07d015e566dc55235094ee4a48407253ca8246c5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Le=C3=B3n=20Orell=20Valerian=20Liehr?= Date: Thu, 23 Apr 2026 21:45:54 +0200 Subject: [PATCH 148/183] Syntactically reject tuple index shorthands in struct patterns to fix a correctness regression --- compiler/rustc_parse/src/parser/expr.rs | 2 +- compiler/rustc_parse/src/parser/mod.rs | 21 +++++++-- compiler/rustc_parse/src/parser/pat.rs | 10 ++-- compiler/rustc_parse/src/parser/ty.rs | 12 +++-- .../struct-expr-pat-tuple-index-shorthand.rs | 19 ++++++++ ...uct-expr-pat-tuple-index-shorthand.stderr} | 16 +++++-- .../parser/struct-field-numeric-shorthand.rs | 8 ---- tests/ui/pattern/self-ctor-133272.stderr | 4 +- tests/ui/self/self_type_keyword.rs | 1 - tests/ui/self/self_type_keyword.stderr | 22 ++++----- .../struct-pat-unmentioned-tuple-indices.rs | 11 +++++ ...truct-pat-unmentioned-tuple-indices.stderr | 41 ++++++++++++++++ tests/ui/structs/struct-tuple-field-names.rs | 18 ------- .../structs/struct-tuple-field-names.stderr | 47 ------------------- ...variant-written-as-empty-struct-variant.rs | 7 +++ ...ant-written-as-empty-struct-variant.stderr | 27 +++++++++++ 16 files changed, 160 insertions(+), 106 deletions(-) create mode 100644 tests/ui/parser/struct-expr-pat-tuple-index-shorthand.rs rename tests/ui/parser/{struct-field-numeric-shorthand.stderr => struct-expr-pat-tuple-index-shorthand.stderr} (55%) delete mode 100644 tests/ui/parser/struct-field-numeric-shorthand.rs create mode 100644 tests/ui/structs/struct-pat-unmentioned-tuple-indices.rs create mode 100644 tests/ui/structs/struct-pat-unmentioned-tuple-indices.stderr delete mode 100644 tests/ui/structs/struct-tuple-field-names.rs delete mode 100644 tests/ui/structs/struct-tuple-field-names.stderr create mode 100644 tests/ui/tuple/tuple-variant-written-as-empty-struct-variant.rs create mode 100644 tests/ui/tuple/tuple-variant-written-as-empty-struct-variant.stderr diff --git a/compiler/rustc_parse/src/parser/expr.rs b/compiler/rustc_parse/src/parser/expr.rs index a0601cc71d032..d55548dd72180 100644 --- a/compiler/rustc_parse/src/parser/expr.rs +++ b/compiler/rustc_parse/src/parser/expr.rs @@ -866,7 +866,7 @@ impl<'a> Parser<'a> { // `raw [ const | mut ]`. let found_raw = self.eat_keyword(exp!(Raw)); assert!(found_raw); - let mutability = self.parse_const_or_mut().unwrap(); + let mutability = self.parse_mut_or_const().unwrap(); (ast::BorrowKind::Raw, mutability) } else { match self.parse_pin_and_mut() { diff --git a/compiler/rustc_parse/src/parser/mod.rs b/compiler/rustc_parse/src/parser/mod.rs index 8c1c3c7025f5e..9303be8ff0ccd 100644 --- a/compiler/rustc_parse/src/parser/mod.rs +++ b/compiler/rustc_parse/src/parser/mod.rs @@ -1302,12 +1302,16 @@ impl<'a> Parser<'a> { Ok(self.mk_expr_with_attrs(span.to(blk_span), kind, attrs)) } - /// Parses mutability (`mut` or nothing). + /// Parse nothing or `mut`. fn parse_mutability(&mut self) -> Mutability { if self.eat_keyword(exp!(Mut)) { Mutability::Mut } else { Mutability::Not } } - /// Parses reference binding mode (`ref`, `ref mut`, `ref pin const`, `ref pin mut`, or nothing). + /// Parse nothing or a by-reference mode. + /// + /// ```ebnf + /// ByRef = "ref" PinAndMut? + /// ``` fn parse_byref(&mut self) -> ByRef { if self.eat_keyword(exp!(Ref)) { let (pinnedness, mutability) = self.parse_pin_and_mut(); @@ -1317,8 +1321,12 @@ impl<'a> Parser<'a> { } } - /// Possibly parses mutability (`const` or `mut`). - fn parse_const_or_mut(&mut self) -> Option { + /// Parse nothing or "explicit" mutability. + /// + /// ```ebnf + /// MutOrConst = "mut" | "const" + /// ``` + fn parse_mut_or_const(&mut self) -> Option { if self.eat_keyword(exp!(Mut)) { Some(Mutability::Mut) } else if self.eat_keyword(exp!(Const)) { @@ -1328,6 +1336,11 @@ impl<'a> Parser<'a> { } } + /// Parse a field name. + /// + /// ```enbf + /// FieldName = IntLit | Ident + /// ``` fn parse_field_name(&mut self) -> PResult<'a, Ident> { if let token::Literal(token::Lit { kind: token::Integer, symbol, suffix }) = self.token.kind { diff --git a/compiler/rustc_parse/src/parser/pat.rs b/compiler/rustc_parse/src/parser/pat.rs index bdcbb1eb42a88..b5c33d740872b 100644 --- a/compiler/rustc_parse/src/parser/pat.rs +++ b/compiler/rustc_parse/src/parser/pat.rs @@ -1731,11 +1731,14 @@ impl<'a> Parser<'a> { self.dcx().emit_err(DotDotDotForRemainingFields { span: self.token.span, token_str }); } + /// Parse a field in a struct pattern. + /// + /// ```ebnf + /// PatField = FieldName ":" Pat | "box"? "mut"? ByRef? Ident + /// ``` fn parse_pat_field(&mut self, lo: Span, attrs: AttrVec) -> PResult<'a, PatField> { - // Check if a colon exists one ahead. This means we're parsing a fieldname. let hi; let (subpat, fieldname, is_shorthand) = if self.look_ahead(1, |t| t == &token::Colon) { - // Parsing a pattern of the form `fieldname: pat`. let fieldname = self.parse_field_name()?; self.bump(); let pat = self.parse_pat_allow_top_guard( @@ -1747,7 +1750,6 @@ impl<'a> Parser<'a> { hi = pat.span; (pat, fieldname, false) } else { - // Parsing a pattern of the form `(box) (ref) (mut) fieldname`. let is_box = self.eat_keyword(exp!(Box)); if is_box { self.psess.gated_spans.gate(sym::box_patterns, self.prev_token.span); @@ -1756,7 +1758,7 @@ impl<'a> Parser<'a> { let mutability = self.parse_mutability(); let by_ref = self.parse_byref(); - let fieldname = self.parse_field_name()?; + let fieldname = self.parse_ident_common(false)?; hi = self.prev_token.span; let ann = BindingMode(by_ref, mutability); let fieldpat = self.mk_pat_ident(boxed_span.to(hi), ann, fieldname); diff --git a/compiler/rustc_parse/src/parser/ty.rs b/compiler/rustc_parse/src/parser/ty.rs index 2a5cd4cd55aec..072975f445bf4 100644 --- a/compiler/rustc_parse/src/parser/ty.rs +++ b/compiler/rustc_parse/src/parser/ty.rs @@ -596,7 +596,7 @@ impl<'a> Parser<'a> { /// Parses a raw pointer with a C-style typo fn parse_ty_c_style_pointer(&mut self) -> PResult<'a, TyKind> { let kw_span = self.token.span; - let mutbl = self.parse_const_or_mut(); + let mutbl = self.parse_mut_or_const(); if let Some(mutbl) = mutbl && self.eat(exp!(Star)) @@ -630,7 +630,7 @@ impl<'a> Parser<'a> { /// Parses a raw pointer type: `*[const | mut] $type`. fn parse_ty_ptr(&mut self) -> PResult<'a, TyKind> { - let mutbl = self.parse_const_or_mut().unwrap_or_else(|| { + let mutbl = self.parse_mut_or_const().unwrap_or_else(|| { let span = self.prev_token.span; self.dcx().emit_err(ExpectedMutOrConstInRawPointerType { span, @@ -774,14 +774,16 @@ impl<'a> Parser<'a> { }) } - /// Parses `pin` and `mut` annotations on references, patterns, or borrow modifiers. + /// Parse nothing, mutability or `pin` followed by "explicit" mutability. /// - /// It must be either `pin const`, `pin mut`, `mut`, or nothing (immutable). + /// ```ebnf + /// PinAndMut = "pin" MutOrConst | "mut" + /// ``` pub(crate) fn parse_pin_and_mut(&mut self) -> (Pinnedness, Mutability) { if self.token.is_ident_named(sym::pin) && self.look_ahead(1, Token::is_mutability) { self.psess.gated_spans.gate(sym::pin_ergonomics, self.token.span); assert!(self.eat_keyword(exp!(Pin))); - let mutbl = self.parse_const_or_mut().unwrap(); + let mutbl = self.parse_mut_or_const().unwrap(); (Pinnedness::Pinned, mutbl) } else { (Pinnedness::Not, self.parse_mutability()) diff --git a/tests/ui/parser/struct-expr-pat-tuple-index-shorthand.rs b/tests/ui/parser/struct-expr-pat-tuple-index-shorthand.rs new file mode 100644 index 0000000000000..fde5563cd4b82 --- /dev/null +++ b/tests/ui/parser/struct-expr-pat-tuple-index-shorthand.rs @@ -0,0 +1,19 @@ +// Check that tuple indices in struct exprs & pats don't have a shorthand. +// If they did it would be possible to bind and reference numeric identifiers +// which is undesirable. + +struct Rgb(u8, u8, u8); + +#[cfg(false)] // ensures that this is a *syntax* error, not just a semantic one! +fn scope() { + // FIXME: Better recover and also report a diagnostic for the other two fields. + let Rgb { 0, 1, 2 }; + //~^ ERROR expected identifier, found `0` + + let _ = Rgb { 0, 1, 2 }; + //~^ ERROR expected identifier, found `0` + //~| ERROR expected identifier, found `1` + //~| ERROR expected identifier, found `2` +} + +fn main() {} diff --git a/tests/ui/parser/struct-field-numeric-shorthand.stderr b/tests/ui/parser/struct-expr-pat-tuple-index-shorthand.stderr similarity index 55% rename from tests/ui/parser/struct-field-numeric-shorthand.stderr rename to tests/ui/parser/struct-expr-pat-tuple-index-shorthand.stderr index 9878cfbbdceb8..5a618f1d3383d 100644 --- a/tests/ui/parser/struct-field-numeric-shorthand.stderr +++ b/tests/ui/parser/struct-expr-pat-tuple-index-shorthand.stderr @@ -1,5 +1,13 @@ error: expected identifier, found `0` - --> $DIR/struct-field-numeric-shorthand.rs:4:19 + --> $DIR/struct-expr-pat-tuple-index-shorthand.rs:10:15 + | +LL | let Rgb { 0, 1, 2 }; + | --- ^ expected identifier + | | + | while parsing the fields for this pattern + +error: expected identifier, found `0` + --> $DIR/struct-expr-pat-tuple-index-shorthand.rs:13:19 | LL | let _ = Rgb { 0, 1, 2 }; | --- ^ expected identifier @@ -7,7 +15,7 @@ LL | let _ = Rgb { 0, 1, 2 }; | while parsing this struct error: expected identifier, found `1` - --> $DIR/struct-field-numeric-shorthand.rs:4:22 + --> $DIR/struct-expr-pat-tuple-index-shorthand.rs:13:22 | LL | let _ = Rgb { 0, 1, 2 }; | --- ^ expected identifier @@ -15,12 +23,12 @@ LL | let _ = Rgb { 0, 1, 2 }; | while parsing this struct error: expected identifier, found `2` - --> $DIR/struct-field-numeric-shorthand.rs:4:25 + --> $DIR/struct-expr-pat-tuple-index-shorthand.rs:13:25 | LL | let _ = Rgb { 0, 1, 2 }; | --- ^ expected identifier | | | while parsing this struct -error: aborting due to 3 previous errors +error: aborting due to 4 previous errors diff --git a/tests/ui/parser/struct-field-numeric-shorthand.rs b/tests/ui/parser/struct-field-numeric-shorthand.rs deleted file mode 100644 index aa342eb02a916..0000000000000 --- a/tests/ui/parser/struct-field-numeric-shorthand.rs +++ /dev/null @@ -1,8 +0,0 @@ -struct Rgb(u8, u8, u8); - -fn main() { - let _ = Rgb { 0, 1, 2 }; - //~^ ERROR expected identifier, found `0` - //~| ERROR expected identifier, found `1` - //~| ERROR expected identifier, found `2` -} diff --git a/tests/ui/pattern/self-ctor-133272.stderr b/tests/ui/pattern/self-ctor-133272.stderr index bca55a43d9c08..f3053a3e7d79a 100644 --- a/tests/ui/pattern/self-ctor-133272.stderr +++ b/tests/ui/pattern/self-ctor-133272.stderr @@ -2,7 +2,9 @@ error: expected identifier, found keyword `Self` --> $DIR/self-ctor-133272.rs:17:21 | LL | let S { ref Self } = todo!(); - | ^^^^ expected identifier, found keyword + | - ^^^^ expected identifier, found keyword + | | + | while parsing the fields for this pattern error[E0422]: cannot find struct, variant or union type `S` in this scope --> $DIR/self-ctor-133272.rs:17:13 diff --git a/tests/ui/self/self_type_keyword.rs b/tests/ui/self/self_type_keyword.rs index 463872585f942..70eb539bb1fd9 100644 --- a/tests/ui/self/self_type_keyword.rs +++ b/tests/ui/self/self_type_keyword.rs @@ -22,7 +22,6 @@ pub fn main() { Foo { Self } => (), //~^ ERROR expected identifier, found keyword `Self` //~| ERROR mismatched types - //~| ERROR `Foo` does not have a field named `Self` } } diff --git a/tests/ui/self/self_type_keyword.stderr b/tests/ui/self/self_type_keyword.stderr index 06761bb40c031..b839bec0b8b7a 100644 --- a/tests/ui/self/self_type_keyword.stderr +++ b/tests/ui/self/self_type_keyword.stderr @@ -39,22 +39,24 @@ error: expected identifier, found keyword `Self` --> $DIR/self_type_keyword.rs:22:15 | LL | Foo { Self } => (), - | ^^^^ expected identifier, found keyword + | --- ^^^^ expected identifier, found keyword + | | + | while parsing the fields for this pattern error: expected identifier, found keyword `Self` - --> $DIR/self_type_keyword.rs:30:26 + --> $DIR/self_type_keyword.rs:29:26 | LL | extern crate core as Self; | ^^^^ expected identifier, found keyword error: expected identifier, found keyword `Self` - --> $DIR/self_type_keyword.rs:35:32 + --> $DIR/self_type_keyword.rs:34:32 | LL | use std::option::Option as Self; | ^^^^ expected identifier, found keyword error: expected identifier, found keyword `Self` - --> $DIR/self_type_keyword.rs:40:11 + --> $DIR/self_type_keyword.rs:39:11 | LL | trait Self {} | ^^^^ expected identifier, found keyword @@ -88,13 +90,7 @@ LL | match 15 { LL | Foo { Self } => (), | ^^^^^^^^^^^^ expected integer, found `Foo` -error[E0026]: struct `Foo` does not have a field named `Self` - --> $DIR/self_type_keyword.rs:22:15 - | -LL | Foo { Self } => (), - | ^^^^ struct `Foo` does not have this field - -error: aborting due to 13 previous errors +error: aborting due to 12 previous errors -Some errors have detailed explanations: E0026, E0308, E0392, E0531. -For more information about an error, try `rustc --explain E0026`. +Some errors have detailed explanations: E0308, E0392, E0531. +For more information about an error, try `rustc --explain E0308`. diff --git a/tests/ui/structs/struct-pat-unmentioned-tuple-indices.rs b/tests/ui/structs/struct-pat-unmentioned-tuple-indices.rs new file mode 100644 index 0000000000000..1f637d34c1abc --- /dev/null +++ b/tests/ui/structs/struct-pat-unmentioned-tuple-indices.rs @@ -0,0 +1,11 @@ +// On unmentioned tuple indices in struct patterns, don't suggest turning the pattern into a +// tuple struct pattern and keep the struct pattern in the suggestion. +// issue: + +struct S(i32, f32); +enum E { V(i32, f32) } + +fn main() { + let S { 0: _ } = S(1, 2.2); //~ ERROR: pattern does not mention field `1` + let E::V { 0: _ } = E::V(1, 2.2); //~ ERROR: pattern does not mention field `1` +} diff --git a/tests/ui/structs/struct-pat-unmentioned-tuple-indices.stderr b/tests/ui/structs/struct-pat-unmentioned-tuple-indices.stderr new file mode 100644 index 0000000000000..bc5480c26bbdc --- /dev/null +++ b/tests/ui/structs/struct-pat-unmentioned-tuple-indices.stderr @@ -0,0 +1,41 @@ +error[E0027]: pattern does not mention field `1` + --> $DIR/struct-pat-unmentioned-tuple-indices.rs:9:9 + | +LL | let S { 0: _ } = S(1, 2.2); + | ^^^^^^^^^^ missing field `1` + | +help: include the missing field in the pattern + | +LL | let S { 0: _, 1: _ } = S(1, 2.2); + | ++++++ +help: if you don't care about this missing field, you can explicitly ignore it + | +LL | let S { 0: _, 1: _ } = S(1, 2.2); + | ++++++ +help: or always ignore missing fields here + | +LL | let S { 0: _, .. } = S(1, 2.2); + | ++++ + +error[E0027]: pattern does not mention field `1` + --> $DIR/struct-pat-unmentioned-tuple-indices.rs:10:9 + | +LL | let E::V { 0: _ } = E::V(1, 2.2); + | ^^^^^^^^^^^^^ missing field `1` + | +help: include the missing field in the pattern + | +LL | let E::V { 0: _, 1: _ } = E::V(1, 2.2); + | ++++++ +help: if you don't care about this missing field, you can explicitly ignore it + | +LL | let E::V { 0: _, 1: _ } = E::V(1, 2.2); + | ++++++ +help: or always ignore missing fields here + | +LL | let E::V { 0: _, .. } = E::V(1, 2.2); + | ++++ + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0027`. diff --git a/tests/ui/structs/struct-tuple-field-names.rs b/tests/ui/structs/struct-tuple-field-names.rs deleted file mode 100644 index 33f264aa25091..0000000000000 --- a/tests/ui/structs/struct-tuple-field-names.rs +++ /dev/null @@ -1,18 +0,0 @@ -struct S(i32, f32); -enum E { - S(i32, f32), -} -fn main() { - let x = E::S(1, 2.2); - match x { - E::S { 0, 1 } => {} - //~^ ERROR tuple variant `E::S` written as struct variant [E0769] - } - let y = S(1, 2.2); - match y { - S { } => {} //~ ERROR: tuple variant `S` written as struct variant [E0769] - } - - if let E::S { 0: a } = x { //~ ERROR: pattern does not mention field `1` - } -} diff --git a/tests/ui/structs/struct-tuple-field-names.stderr b/tests/ui/structs/struct-tuple-field-names.stderr deleted file mode 100644 index 953f01e1fb6cc..0000000000000 --- a/tests/ui/structs/struct-tuple-field-names.stderr +++ /dev/null @@ -1,47 +0,0 @@ -error[E0769]: tuple variant `E::S` written as struct variant - --> $DIR/struct-tuple-field-names.rs:8:9 - | -LL | E::S { 0, 1 } => {} - | ^^^^^^^^^^^^^ - | -help: use the tuple variant pattern syntax instead - | -LL - E::S { 0, 1 } => {} -LL + E::S(_, _) => {} - | - -error[E0769]: tuple variant `S` written as struct variant - --> $DIR/struct-tuple-field-names.rs:13:9 - | -LL | S { } => {} - | ^^^^^ - | -help: use the tuple variant pattern syntax instead - | -LL - S { } => {} -LL + S(_, _) => {} - | - -error[E0027]: pattern does not mention field `1` - --> $DIR/struct-tuple-field-names.rs:16:12 - | -LL | if let E::S { 0: a } = x { - | ^^^^^^^^^^^^^ missing field `1` - | -help: include the missing field in the pattern - | -LL | if let E::S { 0: a, 1: _ } = x { - | ++++++ -help: if you don't care about this missing field, you can explicitly ignore it - | -LL | if let E::S { 0: a, 1: _ } = x { - | ++++++ -help: or always ignore missing fields here - | -LL | if let E::S { 0: a, .. } = x { - | ++++ - -error: aborting due to 3 previous errors - -Some errors have detailed explanations: E0027, E0769. -For more information about an error, try `rustc --explain E0027`. diff --git a/tests/ui/tuple/tuple-variant-written-as-empty-struct-variant.rs b/tests/ui/tuple/tuple-variant-written-as-empty-struct-variant.rs new file mode 100644 index 0000000000000..3382ac9e868a7 --- /dev/null +++ b/tests/ui/tuple/tuple-variant-written-as-empty-struct-variant.rs @@ -0,0 +1,7 @@ +struct S(i32); +enum E { V(i32) } + +fn main() { + let S {} = S(0); //~ ERROR tuple variant `S` written as struct variant + let E::V {} = E::V(0); //~ ERROR tuple variant `E::V` written as struct variant +} diff --git a/tests/ui/tuple/tuple-variant-written-as-empty-struct-variant.stderr b/tests/ui/tuple/tuple-variant-written-as-empty-struct-variant.stderr new file mode 100644 index 0000000000000..ef63238b00406 --- /dev/null +++ b/tests/ui/tuple/tuple-variant-written-as-empty-struct-variant.stderr @@ -0,0 +1,27 @@ +error[E0769]: tuple variant `S` written as struct variant + --> $DIR/tuple-variant-written-as-empty-struct-variant.rs:5:9 + | +LL | let S {} = S(0); + | ^^^^ + | +help: use the tuple variant pattern syntax instead + | +LL - let S {} = S(0); +LL + let S(_) = S(0); + | + +error[E0769]: tuple variant `E::V` written as struct variant + --> $DIR/tuple-variant-written-as-empty-struct-variant.rs:6:9 + | +LL | let E::V {} = E::V(0); + | ^^^^^^^ + | +help: use the tuple variant pattern syntax instead + | +LL - let E::V {} = E::V(0); +LL + let E::V(_) = E::V(0); + | + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0769`. From 87b0ce595c03a811f78ef1b05f1689545cd83392 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Thu, 23 Apr 2026 23:00:38 +0200 Subject: [PATCH 149/183] Remove `AttributeLintKind::MissingOptionsForDiagnosticAttribute` variant --- .../src/attributes/diagnostic/mod.rs | 14 +++++++++----- compiler/rustc_attr_parsing/src/errors.rs | 8 ++++++++ compiler/rustc_lint/src/early/diagnostics.rs | 4 ---- compiler/rustc_lint/src/lints.rs | 8 -------- compiler/rustc_lint_defs/src/lib.rs | 1 - 5 files changed, 17 insertions(+), 18 deletions(-) diff --git a/compiler/rustc_attr_parsing/src/attributes/diagnostic/mod.rs b/compiler/rustc_attr_parsing/src/attributes/diagnostic/mod.rs index 00e753eea97cd..da598d8bac8cd 100644 --- a/compiler/rustc_attr_parsing/src/attributes/diagnostic/mod.rs +++ b/compiler/rustc_attr_parsing/src/attributes/diagnostic/mod.rs @@ -20,7 +20,8 @@ use thin_vec::{ThinVec, thin_vec}; use crate::context::{AcceptContext, Stage}; use crate::errors::{ DisallowedPlaceholder, DisallowedPositionalArgument, IgnoredDiagnosticOption, - InvalidFormatSpecifier, MalFormedDiagnosticAttributeLint, WrappedParserError, + InvalidFormatSpecifier, MalFormedDiagnosticAttributeLint, MissingOptionsForDiagnosticAttribute, + WrappedParserError, }; use crate::parser::{ArgParser, MetaItemListParser, MetaItemOrLitParser, MetaItemParser}; @@ -151,11 +152,14 @@ fn parse_list<'p, S: Stage>( ); } ArgParser::NoArgs => { - cx.emit_lint( + cx.emit_dyn_lint( MALFORMED_DIAGNOSTIC_ATTRIBUTES, - AttributeLintKind::MissingOptionsForDiagnosticAttribute { - attribute: mode.as_str(), - options: mode.expected_options(), + move |dcx, level| { + MissingOptionsForDiagnosticAttribute { + attribute: mode.as_str(), + options: mode.expected_options(), + } + .into_diag(dcx, level) }, span, ); diff --git a/compiler/rustc_attr_parsing/src/errors.rs b/compiler/rustc_attr_parsing/src/errors.rs index b421e85688958..34558c8c057ed 100644 --- a/compiler/rustc_attr_parsing/src/errors.rs +++ b/compiler/rustc_attr_parsing/src/errors.rs @@ -392,3 +392,11 @@ pub(crate) struct IgnoredDiagnosticOption { #[label("`{$option_name}` is later redundantly declared here")] pub later_span: Span, } + +#[derive(Diagnostic)] +#[diag("missing options for `{$attribute}` attribute")] +#[help("{$options}")] +pub(crate) struct MissingOptionsForDiagnosticAttribute { + pub attribute: &'static str, + pub options: &'static str, +} diff --git a/compiler/rustc_lint/src/early/diagnostics.rs b/compiler/rustc_lint/src/early/diagnostics.rs index 29c302ff2802a..40623a4af6cef 100644 --- a/compiler/rustc_lint/src/early/diagnostics.rs +++ b/compiler/rustc_lint/src/early/diagnostics.rs @@ -43,10 +43,6 @@ impl<'a> Diagnostic<'a, ()> for DecorateAttrLint<'_, '_, '_> { .into_diag(dcx, level) } - &AttributeLintKind::MissingOptionsForDiagnosticAttribute { attribute, options } => { - lints::MissingOptionsForDiagnosticAttribute { attribute, options } - .into_diag(dcx, level) - } &AttributeLintKind::NonMetaItemDiagnosticAttribute => { lints::NonMetaItemDiagnosticAttribute.into_diag(dcx, level) } diff --git a/compiler/rustc_lint/src/lints.rs b/compiler/rustc_lint/src/lints.rs index c2c140a3c6d92..0fc9ed8116f57 100644 --- a/compiler/rustc_lint/src/lints.rs +++ b/compiler/rustc_lint/src/lints.rs @@ -3282,14 +3282,6 @@ impl Subdiagnostic for MismatchedLifetimeSyntaxesSuggestion { } } -#[derive(Diagnostic)] -#[diag("missing options for `{$attribute}` attribute")] -#[help("{$options}")] -pub(crate) struct MissingOptionsForDiagnosticAttribute { - pub attribute: &'static str, - pub options: &'static str, -} - #[derive(Diagnostic)] #[diag("`Eq::assert_receiver_is_total_eq` should never be implemented by hand")] #[note("this method was used to add checks to the `Eq` derive macro")] diff --git a/compiler/rustc_lint_defs/src/lib.rs b/compiler/rustc_lint_defs/src/lib.rs index aef62c768337b..5df038e3124a2 100644 --- a/compiler/rustc_lint_defs/src/lib.rs +++ b/compiler/rustc_lint_defs/src/lib.rs @@ -656,7 +656,6 @@ pub enum DeprecatedSinceKind { pub enum AttributeLintKind { UnexpectedCfgName((Symbol, Span), Option<(Symbol, Span)>), UnexpectedCfgValue((Symbol, Span), Option<(Symbol, Span)>), - MissingOptionsForDiagnosticAttribute { attribute: &'static str, options: &'static str }, NonMetaItemDiagnosticAttribute, } From 7a07b795737d798b90c82a7edb02cc4287039d67 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Thu, 23 Apr 2026 23:08:40 +0200 Subject: [PATCH 150/183] Remove `AttributeLintKind::NonMetaItemDiagnosticAttribute` variant --- .../rustc_attr_parsing/src/attributes/diagnostic/mod.rs | 8 ++++---- compiler/rustc_attr_parsing/src/errors.rs | 7 +++++++ compiler/rustc_lint/src/early/diagnostics.rs | 6 ------ compiler/rustc_lint/src/lints.rs | 7 ------- compiler/rustc_lint_defs/src/lib.rs | 1 - 5 files changed, 11 insertions(+), 18 deletions(-) diff --git a/compiler/rustc_attr_parsing/src/attributes/diagnostic/mod.rs b/compiler/rustc_attr_parsing/src/attributes/diagnostic/mod.rs index da598d8bac8cd..53491a0a959ac 100644 --- a/compiler/rustc_attr_parsing/src/attributes/diagnostic/mod.rs +++ b/compiler/rustc_attr_parsing/src/attributes/diagnostic/mod.rs @@ -6,7 +6,7 @@ use rustc_hir::attrs::diagnostic::{ Directive, FilterFormatString, Flag, FormatArg, FormatString, LitOrArg, Name, NameValue, OnUnimplementedCondition, Piece, Predicate, }; -use rustc_hir::lints::{AttributeLintKind, FormatWarning}; +use rustc_hir::lints::FormatWarning; use rustc_macros::Diagnostic; use rustc_parse_format::{ Argument, FormatSpec, ParseError, ParseMode, Parser, Piece as RpfPiece, Position, @@ -21,7 +21,7 @@ use crate::context::{AcceptContext, Stage}; use crate::errors::{ DisallowedPlaceholder, DisallowedPositionalArgument, IgnoredDiagnosticOption, InvalidFormatSpecifier, MalFormedDiagnosticAttributeLint, MissingOptionsForDiagnosticAttribute, - WrappedParserError, + NonMetaItemDiagnosticAttribute, WrappedParserError, }; use crate::parser::{ArgParser, MetaItemListParser, MetaItemOrLitParser, MetaItemParser}; @@ -145,9 +145,9 @@ fn parse_list<'p, S: Stage>( // We're dealing with `#[diagnostic::attr()]`. // This can be because that is what the user typed, but that's also what we'd see // if the user used non-metaitem syntax. See `ArgParser::from_attr_args`. - cx.emit_lint( + cx.emit_dyn_lint( MALFORMED_DIAGNOSTIC_ATTRIBUTES, - AttributeLintKind::NonMetaItemDiagnosticAttribute, + move |dcx, level| NonMetaItemDiagnosticAttribute.into_diag(dcx, level), list.span, ); } diff --git a/compiler/rustc_attr_parsing/src/errors.rs b/compiler/rustc_attr_parsing/src/errors.rs index 34558c8c057ed..95d0e82f472c0 100644 --- a/compiler/rustc_attr_parsing/src/errors.rs +++ b/compiler/rustc_attr_parsing/src/errors.rs @@ -400,3 +400,10 @@ pub(crate) struct MissingOptionsForDiagnosticAttribute { pub attribute: &'static str, pub options: &'static str, } + +#[derive(Diagnostic)] +#[diag("expected a literal or missing delimiter")] +#[help( + "only literals are allowed as values for the `message`, `note` and `label` options. These options must be separated by a comma" +)] +pub(crate) struct NonMetaItemDiagnosticAttribute; diff --git a/compiler/rustc_lint/src/early/diagnostics.rs b/compiler/rustc_lint/src/early/diagnostics.rs index 40623a4af6cef..a4cb4e5320672 100644 --- a/compiler/rustc_lint/src/early/diagnostics.rs +++ b/compiler/rustc_lint/src/early/diagnostics.rs @@ -6,8 +6,6 @@ use rustc_hir::lints::AttributeLintKind; use rustc_middle::ty::TyCtxt; use rustc_session::Session; -use crate::lints; - mod check_cfg; pub struct DiagAndSess<'sess> { @@ -42,10 +40,6 @@ impl<'a> Diagnostic<'a, ()> for DecorateAttrLint<'_, '_, '_> { check_cfg::unexpected_cfg_value(self.sess, self.tcx, name, value) .into_diag(dcx, level) } - - &AttributeLintKind::NonMetaItemDiagnosticAttribute => { - lints::NonMetaItemDiagnosticAttribute.into_diag(dcx, level) - } } } } diff --git a/compiler/rustc_lint/src/lints.rs b/compiler/rustc_lint/src/lints.rs index 0fc9ed8116f57..05914686705a6 100644 --- a/compiler/rustc_lint/src/lints.rs +++ b/compiler/rustc_lint/src/lints.rs @@ -3286,10 +3286,3 @@ impl Subdiagnostic for MismatchedLifetimeSyntaxesSuggestion { #[diag("`Eq::assert_receiver_is_total_eq` should never be implemented by hand")] #[note("this method was used to add checks to the `Eq` derive macro")] pub(crate) struct EqInternalMethodImplemented; - -#[derive(Diagnostic)] -#[diag("expected a literal or missing delimiter")] -#[help( - "only literals are allowed as values for the `message`, `note` and `label` options. These options must be separated by a comma" -)] -pub(crate) struct NonMetaItemDiagnosticAttribute; diff --git a/compiler/rustc_lint_defs/src/lib.rs b/compiler/rustc_lint_defs/src/lib.rs index 5df038e3124a2..0a9c0669a5bd3 100644 --- a/compiler/rustc_lint_defs/src/lib.rs +++ b/compiler/rustc_lint_defs/src/lib.rs @@ -656,7 +656,6 @@ pub enum DeprecatedSinceKind { pub enum AttributeLintKind { UnexpectedCfgName((Symbol, Span), Option<(Symbol, Span)>), UnexpectedCfgValue((Symbol, Span), Option<(Symbol, Span)>), - NonMetaItemDiagnosticAttribute, } #[derive(Debug, Clone, HashStable_Generic)] From 874b7d31416fdfcad39f7f8f0179868cecac8cf6 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Thu, 23 Apr 2026 15:19:05 -0700 Subject: [PATCH 151/183] Remove myself as a maintainer of `wasm32-wasip1-threads` Over time the landscape for myself has changed, and I no longer would like to be officially listed as a maintainer of this target in Rust, so I'm going to step down. There are still a number of others listed on this target, however, so I'm sure they can address issues should they come up. --- src/doc/rustc/src/platform-support/wasm32-wasip1-threads.md | 1 - 1 file changed, 1 deletion(-) diff --git a/src/doc/rustc/src/platform-support/wasm32-wasip1-threads.md b/src/doc/rustc/src/platform-support/wasm32-wasip1-threads.md index 6c8bf21ec1997..cc66b2fdc6dcb 100644 --- a/src/doc/rustc/src/platform-support/wasm32-wasip1-threads.md +++ b/src/doc/rustc/src/platform-support/wasm32-wasip1-threads.md @@ -19,7 +19,6 @@ with native multi threading capabilities. ## Target maintainers [@g0djan](https://github.com/g0djan) -[@alexcrichton](https://github.com/alexcrichton) [@abrown](https://github.com/abrown) [@loganek](https://github.com/loganek) From 250beb317422dad63d9bdefee9d82c55a732ba60 Mon Sep 17 00:00:00 2001 From: dianqk Date: Fri, 24 Apr 2026 06:36:07 +0800 Subject: [PATCH 152/183] explicit-tail-calls: disable two tests on LoongArch for LLVM 22 also Tail call support for LoongArch was reverted in LLVM 22 also. --- tests/ui/explicit-tail-calls/support/bystack.rs | 4 ++-- tests/ui/explicit-tail-calls/support/byval.rs | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/tests/ui/explicit-tail-calls/support/bystack.rs b/tests/ui/explicit-tail-calls/support/bystack.rs index 0f10fe3d172ec..ddd9c79f5c72f 100644 --- a/tests/ui/explicit-tail-calls/support/bystack.rs +++ b/tests/ui/explicit-tail-calls/support/bystack.rs @@ -36,11 +36,11 @@ //@ revisions: loongarch32 //@[loongarch32] compile-flags: --target loongarch32-unknown-none //@[loongarch32] needs-llvm-components: loongarch -//@[loongarch32] ignore-llvm-version: 23 +//@[loongarch32] ignore-llvm-version: 22 - 23 //@ revisions: loongarch64 //@[loongarch64] compile-flags: --target loongarch64-unknown-linux-gnu //@[loongarch64] needs-llvm-components: loongarch -//@[loongarch64] ignore-llvm-version: 23 +//@[loongarch64] ignore-llvm-version: 22 - 23 //@ revisions: bpf //@[bpf] compile-flags: --target bpfeb-unknown-none //@[bpf] needs-llvm-components: bpf diff --git a/tests/ui/explicit-tail-calls/support/byval.rs b/tests/ui/explicit-tail-calls/support/byval.rs index be11741fd0165..f451a953f2aae 100644 --- a/tests/ui/explicit-tail-calls/support/byval.rs +++ b/tests/ui/explicit-tail-calls/support/byval.rs @@ -36,11 +36,11 @@ //@ revisions: loongarch32 //@[loongarch32] compile-flags: --target loongarch32-unknown-none //@[loongarch32] needs-llvm-components: loongarch -//@[loongarch32] ignore-llvm-version: 23 +//@[loongarch32] ignore-llvm-version: 22 - 23 //@ revisions: loongarch64 //@[loongarch64] compile-flags: --target loongarch64-unknown-linux-gnu //@[loongarch64] needs-llvm-components: loongarch -//@[loongarch64] ignore-llvm-version: 23 +//@[loongarch64] ignore-llvm-version: 22 - 23 //@ revisions: bpf //@[bpf] compile-flags: --target bpfeb-unknown-none //@[bpf] needs-llvm-components: bpf From 804e419ed85bbcaf99d1a3385cfef3bf3105cd05 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Wed, 22 Apr 2026 13:44:43 +1000 Subject: [PATCH 153/183] Eliminate `CrateMetadataRef`. There are a number of things I dislike about `CrateMetadataRef`. - It contains two fields `cstore` and `cdata`. The latter points to data within the former. It's like having an `Elem` type that has a reference to a vec element and also a reference to the vec itself. Weird. - The `cdata` field gets a lot of use, and the `Deref` impl just derefs that field. The `cstore` field is rarely used. - `CrateMetadataRef` is not a good name. - Variables named `cdata` sometimes refer to values of this type and sometimes to values of type `CrateMetadata`, which is confusing. The good news is that `CrateMetadataRef` is not necessary and can be replaced with `&CrateMetadata`. Why? Everywhere that `CrateMetadataRef` is used, a `TyCtxt` is also present, and the `CStore` is accessible from the `TyCtxt` with `CStore::from_tcx`. So this commit removes `CrateMetadataRef` and replaces all its uses with `&CrateMetadata`. Notes: - This requires adding only two uses of `CStore::from_tcx`, which shows how rarely the `cstore` field was used. - `get_crate_data` now matches `get_crate_data_mut` more closely. - A few variables are renamed for consistency, e.g. `data`/`cmeta` -> `cdata`. - An unnecessary local variable (`local_cdata`) in `decode_expn_id` is removed. - All the `CrateMetadataRef` methods become `CrateMetadata` methods, and their receiver changes from `self` to `&self`. - `RawDefId::decode_from_cdata` is inlined and removed, because it has a single call site. --- compiler/rustc_metadata/src/creader.rs | 54 ++-- compiler/rustc_metadata/src/rmeta/decoder.rs | 267 ++++++++---------- .../src/rmeta/decoder/cstore_impl.rs | 48 ++-- compiler/rustc_metadata/src/rmeta/mod.rs | 9 +- 4 files changed, 165 insertions(+), 213 deletions(-) diff --git a/compiler/rustc_metadata/src/creader.rs b/compiler/rustc_metadata/src/creader.rs index feeb38830e0a9..9a756337335c0 100644 --- a/compiler/rustc_metadata/src/creader.rs +++ b/compiler/rustc_metadata/src/creader.rs @@ -111,21 +111,6 @@ enum LoadResult { Loaded(Library), } -/// A reference to `CrateMetadata` that can also give access to whole crate store when necessary. -#[derive(Clone, Copy)] -pub(crate) struct CrateMetadataRef<'a> { - pub cdata: &'a CrateMetadata, - pub cstore: &'a CStore, -} - -impl std::ops::Deref for CrateMetadataRef<'_> { - type Target = CrateMetadata; - - fn deref(&self) -> &Self::Target { - self.cdata - } -} - struct CrateDump<'a>(&'a CStore); impl<'a> std::fmt::Debug for CrateDump<'a> { @@ -245,11 +230,8 @@ impl CStore { self.metas[cnum].is_some() } - pub(crate) fn get_crate_data(&self, cnum: CrateNum) -> CrateMetadataRef<'_> { - let cdata = self.metas[cnum] - .as_ref() - .unwrap_or_else(|| panic!("Failed to get crate data for {cnum:?}")); - CrateMetadataRef { cdata, cstore: self } + pub(crate) fn get_crate_data(&self, cnum: CrateNum) -> &CrateMetadata { + self.metas[cnum].as_ref().unwrap_or_else(|| panic!("Failed to get crate data for {cnum:?}")) } pub(crate) fn get_crate_data_mut(&mut self, cnum: CrateNum) -> &mut CrateMetadata { @@ -284,14 +266,13 @@ impl CStore { } pub fn all_proc_macro_def_ids(&self, tcx: TyCtxt<'_>) -> impl Iterator { - self.iter_crate_data() - .flat_map(move |(krate, data)| data.proc_macros_for_crate(tcx, krate, self)) + self.iter_crate_data().flat_map(move |(krate, data)| data.proc_macros_for_crate(tcx, krate)) } fn push_dependencies_in_postorder(&self, deps: &mut IndexSet, cnum: CrateNum) { if !deps.contains(&cnum) { - let data = self.get_crate_data(cnum); - for dep in data.dependencies() { + let cdata = self.get_crate_data(cnum); + for dep in cdata.dependencies() { if dep != cnum { self.push_dependencies_in_postorder(deps, dep); } @@ -676,7 +657,6 @@ impl CStore { let crate_metadata = CrateMetadata::new( tcx, - self, metadata, crate_root, raw_proc_macros, @@ -865,12 +845,12 @@ impl CStore { // `private-dependency` when `register_crate` is called for the first time. Then it must be updated to // `public-dependency` here. let private_dep = self.is_private_dep(&tcx.sess.opts.externs, name, private_dep); - let data = self.get_crate_data_mut(cnum); - if data.is_proc_macro_crate() { + let cdata = self.get_crate_data_mut(cnum); + if cdata.is_proc_macro_crate() { dep_kind = CrateDepKind::MacrosOnly; } - data.set_dep_kind(cmp::max(data.dep_kind(), dep_kind)); - data.update_and_private_dep(private_dep); + cdata.set_dep_kind(cmp::max(cdata.dep_kind(), dep_kind)); + cdata.update_and_private_dep(private_dep); Ok(cnum) } (LoadResult::Loaded(library), host_library) => { @@ -1045,14 +1025,14 @@ impl CStore { ) else { return; }; - let data = self.get_crate_data(cnum); + let cdata = self.get_crate_data(cnum); // Sanity check the loaded crate to ensure it is indeed a panic runtime // and the panic strategy is indeed what we thought it was. - if !data.is_panic_runtime() { + if !cdata.is_panic_runtime() { tcx.dcx().emit_err(errors::CrateNotPanicRuntime { crate_name: name }); } - if data.required_panic_strategy() != Some(desired_strategy) { + if cdata.required_panic_strategy() != Some(desired_strategy) { tcx.dcx() .emit_err(errors::NoPanicStrategy { crate_name: name, strategy: desired_strategy }); } @@ -1086,10 +1066,10 @@ impl CStore { ) else { return; }; - let data = self.get_crate_data(cnum); + let cdata = self.get_crate_data(cnum); // Sanity check the loaded crate to ensure it is indeed a profiler runtime - if !data.is_profiler_runtime() { + if !cdata.is_profiler_runtime() { tcx.dcx().emit_err(errors::NotProfilerRuntime { crate_name: name }); } } @@ -1243,9 +1223,9 @@ impl CStore { }; // Sanity check that the loaded crate is `#![compiler_builtins]` - let cmeta = self.get_crate_data(cnum); - if !cmeta.is_compiler_builtins() { - tcx.dcx().emit_err(errors::CrateNotCompilerBuiltins { crate_name: cmeta.name() }); + let cdata = self.get_crate_data(cnum); + if !cdata.is_compiler_builtins() { + tcx.dcx().emit_err(errors::CrateNotCompilerBuiltins { crate_name: cdata.name() }); } } diff --git a/compiler/rustc_metadata/src/rmeta/decoder.rs b/compiler/rustc_metadata/src/rmeta/decoder.rs index 181dbfa126d73..230ce5686e979 100644 --- a/compiler/rustc_metadata/src/rmeta/decoder.rs +++ b/compiler/rustc_metadata/src/rmeta/decoder.rs @@ -221,10 +221,11 @@ impl<'a> LazyDecoder for BlobDecodeContext<'a> { /// This is the decode context used when crate metadata was already read. /// Decoding of some types, like `Span` require some information to already been read. -/// Can be constructed from a [`TyCtxt`] and [`CrateMetadataRef`] (see the [`MetaDecoder`] trait) +/// Can be constructed from a [`TyCtxt`] and [`CrateMetadata`] (see impls of the [`MetaDecoder`] +/// trait). pub(super) struct MetadataDecodeContext<'a, 'tcx> { blob_decoder: BlobDecodeContext<'a>, - cdata: CrateMetadataRef<'a>, + cdata: &'a CrateMetadata, tcx: TyCtxt<'tcx>, // Used for decoding interpret::AllocIds in a cached & thread-safe manner. @@ -296,15 +297,15 @@ impl<'a> MetaBlob<'a> for &'a CrateMetadata { } } -impl<'a, 'tcx> MetaDecoder for (CrateMetadataRef<'a>, TyCtxt<'tcx>) { +impl<'a, 'tcx> MetaDecoder for (&'a CrateMetadata, TyCtxt<'tcx>) { type Context = MetadataDecodeContext<'a, 'tcx>; fn decoder(self, pos: usize) -> MetadataDecodeContext<'a, 'tcx> { MetadataDecodeContext { - blob_decoder: self.0.cdata.blob().decoder(pos), + blob_decoder: self.0.blob().decoder(pos), cdata: self.0, tcx: self.1, - alloc_decoding_session: self.0.cdata.alloc_decoding_state.new_decoding_session(), + alloc_decoding_session: self.0.alloc_decoding_state.new_decoding_session(), } } } @@ -472,15 +473,13 @@ impl<'a, 'tcx> SpanDecoder for MetadataDecodeContext<'a, 'tcx> { cdata .root .syntax_contexts - .get(cdata.cdata, id) + .get(cdata, id) .unwrap_or_else(|| panic!("Missing SyntaxContext {id:?} for crate {cname:?}")) .decode((cdata, tcx)) }) } fn decode_expn_id(&mut self) -> ExpnId { - let local_cdata = self.cdata; - let tcx = self.tcx; let cnum = CrateNum::decode(self); let index = u32::decode(self); @@ -490,23 +489,15 @@ impl<'a, 'tcx> SpanDecoder for MetadataDecodeContext<'a, 'tcx> { // Lookup local `ExpnData`s in our own crate data. Foreign `ExpnData`s // are stored in the owning crate, to avoid duplication. debug_assert_ne!(cnum, LOCAL_CRATE); - let crate_data = if cnum == local_cdata.cnum { - local_cdata + let cstore; + let cdata = if cnum == self.cdata.cnum { + self.cdata } else { - local_cdata.cstore.get_crate_data(cnum) + cstore = CStore::from_tcx(tcx); + cstore.get_crate_data(cnum) }; - let expn_data = crate_data - .root - .expn_data - .get(crate_data.cdata, index) - .unwrap() - .decode((crate_data, tcx)); - let expn_hash = crate_data - .root - .expn_hashes - .get(crate_data.cdata, index) - .unwrap() - .decode((crate_data, tcx)); + let expn_data = cdata.root.expn_data.get(cdata, index).unwrap().decode((cdata, tcx)); + let expn_hash = cdata.root.expn_hashes.get(cdata, index).unwrap().decode((cdata, tcx)); (expn_data, expn_hash) }); expn_id @@ -639,8 +630,9 @@ impl<'a, 'tcx> Decodable> for SpanData { cnum ); - let foreign_data = decoder.cdata.cstore.get_crate_data(cnum); - foreign_data.imported_source_file(tcx, metadata_index) + let cstore = CStore::from_tcx(tcx); + let foreign_cdata = cstore.get_crate_data(cnum); + foreign_cdata.imported_source_file(tcx, metadata_index) }; // Make sure our span is well-formed. @@ -979,12 +971,12 @@ impl CrateRoot { } } -impl<'a> CrateMetadataRef<'a> { - fn missing(self, descr: &str, id: DefIndex) -> ! { +impl CrateMetadata { + fn missing(&self, descr: &str, id: DefIndex) -> ! { bug!("missing `{descr}` for {:?}", self.local_def_id(id)) } - fn raw_proc_macro(self, tcx: TyCtxt<'_>, id: DefIndex) -> &'a ProcMacro { + fn raw_proc_macro(&self, tcx: TyCtxt<'_>, id: DefIndex) -> &ProcMacro { // DefIndex's in root.proc_macro_data have a one-to-one correspondence // with items in 'raw_proc_macros'. let pos = self @@ -999,7 +991,7 @@ impl<'a> CrateMetadataRef<'a> { &self.raw_proc_macros.unwrap()[pos] } - fn opt_item_name(self, item_index: DefIndex) -> Option { + fn opt_item_name(&self, item_index: DefIndex) -> Option { let def_key = self.def_key(item_index); def_key.disambiguated_data.data.get_opt_name().or_else(|| { if def_key.disambiguated_data.data == DefPathData::Ctor { @@ -1011,49 +1003,49 @@ impl<'a> CrateMetadataRef<'a> { }) } - fn item_name(self, item_index: DefIndex) -> Symbol { + fn item_name(&self, item_index: DefIndex) -> Symbol { self.opt_item_name(item_index).expect("no encoded ident for item") } - fn opt_item_ident(self, tcx: TyCtxt<'_>, item_index: DefIndex) -> Option { + fn opt_item_ident(&self, tcx: TyCtxt<'_>, item_index: DefIndex) -> Option { let name = self.opt_item_name(item_index)?; let span = self .root .tables .def_ident_span - .get(self.cdata, item_index) + .get(self, item_index) .unwrap_or_else(|| self.missing("def_ident_span", item_index)) .decode((self, tcx)); Some(Ident::new(name, span)) } - fn item_ident(self, tcx: TyCtxt<'_>, item_index: DefIndex) -> Ident { + fn item_ident(&self, tcx: TyCtxt<'_>, item_index: DefIndex) -> Ident { self.opt_item_ident(tcx, item_index).expect("no encoded ident for item") } #[inline] - pub(super) fn map_encoded_cnum_to_current(self, cnum: CrateNum) -> CrateNum { + pub(super) fn map_encoded_cnum_to_current(&self, cnum: CrateNum) -> CrateNum { if cnum == LOCAL_CRATE { self.cnum } else { self.cnum_map[cnum] } } - fn def_kind(self, item_id: DefIndex) -> DefKind { + fn def_kind(&self, item_id: DefIndex) -> DefKind { self.root .tables .def_kind - .get(self.cdata, item_id) + .get(self, item_id) .unwrap_or_else(|| self.missing("def_kind", item_id)) } - fn get_span(self, tcx: TyCtxt<'_>, index: DefIndex) -> Span { + fn get_span(&self, tcx: TyCtxt<'_>, index: DefIndex) -> Span { self.root .tables .def_span - .get(self.cdata, index) + .get(self, index) .unwrap_or_else(|| self.missing("def_span", index)) .decode((self, tcx)) } - fn load_proc_macro<'tcx>(self, tcx: TyCtxt<'tcx>, id: DefIndex) -> SyntaxExtension { + fn load_proc_macro<'tcx>(&self, tcx: TyCtxt<'tcx>, id: DefIndex) -> SyntaxExtension { let (name, kind, helper_attrs) = match *self.raw_proc_macro(tcx, id) { ProcMacro::CustomDerive { trait_name, attributes, client } => { let helper_attrs = @@ -1087,7 +1079,7 @@ impl<'a> CrateMetadataRef<'a> { } fn get_variant( - self, + &self, tcx: TyCtxt<'_>, kind: DefKind, index: DefIndex, @@ -1100,8 +1092,7 @@ impl<'a> CrateMetadataRef<'a> { _ => bug!(), }; - let data = - self.root.tables.variant_data.get(self.cdata, index).unwrap().decode((self, tcx)); + let data = self.root.tables.variant_data.get(self, index).unwrap().decode((self, tcx)); let variant_did = if adt_kind == ty::AdtKind::Enum { Some(self.local_def_id(index)) } else { None }; @@ -1130,7 +1121,7 @@ impl<'a> CrateMetadataRef<'a> { ) } - fn get_adt_def<'tcx>(self, tcx: TyCtxt<'tcx>, item_id: DefIndex) -> ty::AdtDef<'tcx> { + fn get_adt_def<'tcx>(&self, tcx: TyCtxt<'tcx>, item_id: DefIndex) -> ty::AdtDef<'tcx> { let kind = self.def_kind(item_id); let did = self.local_def_id(item_id); @@ -1140,14 +1131,13 @@ impl<'a> CrateMetadataRef<'a> { DefKind::Union => ty::AdtKind::Union, _ => bug!("get_adt_def called on a non-ADT {:?}", did), }; - let repr = - self.root.tables.repr_options.get(self.cdata, item_id).unwrap().decode((self, tcx)); + let repr = self.root.tables.repr_options.get(self, item_id).unwrap().decode((self, tcx)); let mut variants: Vec<_> = if let ty::AdtKind::Enum = adt_kind { self.root .tables .module_children_non_reexports - .get(self.cdata, item_id) + .get(self, item_id) .expect("variants are not encoded for an enum") .decode((self, tcx)) .filter_map(|index| { @@ -1172,39 +1162,39 @@ impl<'a> CrateMetadataRef<'a> { ) } - fn get_visibility(self, tcx: TyCtxt<'_>, id: DefIndex) -> Visibility { + fn get_visibility(&self, tcx: TyCtxt<'_>, id: DefIndex) -> Visibility { self.root .tables .visibility - .get(self.cdata, id) + .get(self, id) .unwrap_or_else(|| self.missing("visibility", id)) .decode((self, tcx)) .map_id(|index| self.local_def_id(index)) } - fn get_safety(self, id: DefIndex) -> Safety { - self.root.tables.safety.get(self.cdata, id) + fn get_safety(&self, id: DefIndex) -> Safety { + self.root.tables.safety.get(self, id) } - fn get_default_field(self, tcx: TyCtxt<'_>, id: DefIndex) -> Option { - self.root.tables.default_fields.get(self.cdata, id).map(|d| d.decode((self, tcx))) + fn get_default_field(&self, tcx: TyCtxt<'_>, id: DefIndex) -> Option { + self.root.tables.default_fields.get(self, id).map(|d| d.decode((self, tcx))) } - fn get_expn_that_defined(self, tcx: TyCtxt<'_>, id: DefIndex) -> ExpnId { + fn get_expn_that_defined(&self, tcx: TyCtxt<'_>, id: DefIndex) -> ExpnId { self.root .tables .expn_that_defined - .get(self.cdata, id) + .get(self, id) .unwrap_or_else(|| self.missing("expn_that_defined", id)) .decode((self, tcx)) } - fn get_debugger_visualizers(self, tcx: TyCtxt<'_>) -> Vec { + fn get_debugger_visualizers(&self, tcx: TyCtxt<'_>) -> Vec { self.root.debugger_visualizers.decode((self, tcx)).collect::>() } /// Iterates over all the stability attributes in the given crate. - fn get_lib_features(self, tcx: TyCtxt<'_>) -> LibFeatures { + fn get_lib_features(&self, tcx: TyCtxt<'_>) -> LibFeatures { LibFeatures { stability: self .root @@ -1218,12 +1208,12 @@ impl<'a> CrateMetadataRef<'a> { /// Iterates over the stability implications in the given crate (when a `#[unstable]` attribute /// has an `implied_by` meta item, then the mapping from the implied feature to the actual /// feature is a stability implication). - fn get_stability_implications<'tcx>(self, tcx: TyCtxt<'tcx>) -> &'tcx [(Symbol, Symbol)] { + fn get_stability_implications<'tcx>(&self, tcx: TyCtxt<'tcx>) -> &'tcx [(Symbol, Symbol)] { tcx.arena.alloc_from_iter(self.root.stability_implications.decode((self, tcx))) } /// Iterates over the lang items in the given crate. - fn get_lang_items<'tcx>(self, tcx: TyCtxt<'tcx>) -> &'tcx [(DefId, LangItem)] { + fn get_lang_items<'tcx>(&self, tcx: TyCtxt<'tcx>) -> &'tcx [(DefId, LangItem)] { tcx.arena.alloc_from_iter( self.root .lang_items @@ -1233,7 +1223,7 @@ impl<'a> CrateMetadataRef<'a> { } fn get_stripped_cfg_items<'tcx>( - self, + &self, tcx: TyCtxt<'tcx>, cnum: CrateNum, ) -> &'tcx [StrippedCfgItem] { @@ -1246,7 +1236,7 @@ impl<'a> CrateMetadataRef<'a> { } /// Iterates over the diagnostic items in the given crate. - fn get_diagnostic_items(self, tcx: TyCtxt<'_>) -> DiagnosticItems { + fn get_diagnostic_items(&self, tcx: TyCtxt<'_>) -> DiagnosticItems { let mut id_to_name = DefIdMap::default(); let name_to_id = self .root @@ -1261,7 +1251,7 @@ impl<'a> CrateMetadataRef<'a> { DiagnosticItems { id_to_name, name_to_id } } - fn get_mod_child(self, tcx: TyCtxt<'_>, id: DefIndex) -> ModChild { + fn get_mod_child(&self, tcx: TyCtxt<'_>, id: DefIndex) -> ModChild { let ident = self.item_ident(tcx, id); let res = Res::Def(self.def_kind(id), self.local_def_id(id)); let vis = self.get_visibility(tcx, id); @@ -1273,7 +1263,7 @@ impl<'a> CrateMetadataRef<'a> { /// including both proper items and reexports. /// Module here is understood in name resolution sense - it can be a `mod` item, /// or a crate root, or an enum, or a trait. - fn get_module_children(self, tcx: TyCtxt<'_>, id: DefIndex) -> impl Iterator { + fn get_module_children(&self, tcx: TyCtxt<'_>, id: DefIndex) -> impl Iterator { gen move { if let Some(data) = &self.root.proc_macro_data { // If we are loading as a proc macro, we want to return @@ -1285,13 +1275,12 @@ impl<'a> CrateMetadataRef<'a> { } } else { // Iterate over all children. - let non_reexports = - self.root.tables.module_children_non_reexports.get(self.cdata, id); + let non_reexports = self.root.tables.module_children_non_reexports.get(self, id); for child_index in non_reexports.unwrap().decode((self, tcx)) { yield self.get_mod_child(tcx, child_index); } - let reexports = self.root.tables.module_children_reexports.get(self.cdata, id); + let reexports = self.root.tables.module_children_reexports.get(self, id); if !reexports.is_default() { for reexport in reexports.decode((self, tcx)) { yield reexport; @@ -1302,12 +1291,12 @@ impl<'a> CrateMetadataRef<'a> { } fn get_ambig_module_children( - self, + &self, tcx: TyCtxt<'_>, id: DefIndex, ) -> impl Iterator { gen move { - let children = self.root.tables.ambig_module_children.get(self.cdata, id); + let children = self.root.tables.ambig_module_children.get(self, id); if !children.is_default() { for child in children.decode((self, tcx)) { yield child; @@ -1316,15 +1305,15 @@ impl<'a> CrateMetadataRef<'a> { } } - fn is_item_mir_available(self, id: DefIndex) -> bool { - self.root.tables.optimized_mir.get(self.cdata, id).is_some() + fn is_item_mir_available(&self, id: DefIndex) -> bool { + self.root.tables.optimized_mir.get(self, id).is_some() } - fn get_fn_has_self_parameter(self, tcx: TyCtxt<'_>, id: DefIndex) -> bool { + fn get_fn_has_self_parameter(&self, tcx: TyCtxt<'_>, id: DefIndex) -> bool { self.root .tables .fn_arg_idents - .get(self.cdata, id) + .get(self, id) .expect("argument names not encoded for a function") .decode((self, tcx)) .nth(0) @@ -1332,20 +1321,20 @@ impl<'a> CrateMetadataRef<'a> { } fn get_associated_item_or_field_def_ids( - self, + &self, tcx: TyCtxt<'_>, id: DefIndex, ) -> impl Iterator { self.root .tables .associated_item_or_field_def_ids - .get(self.cdata, id) + .get(self, id) .unwrap_or_else(|| self.missing("associated_item_or_field_def_ids", id)) .decode((self, tcx)) .map(move |child_index| self.local_def_id(child_index)) } - fn get_associated_item(self, tcx: TyCtxt<'_>, id: DefIndex) -> ty::AssocItem { + fn get_associated_item(&self, tcx: TyCtxt<'_>, id: DefIndex) -> ty::AssocItem { let kind = match self.def_kind(id) { DefKind::AssocConst { is_type_const } => { ty::AssocKind::Const { name: self.item_name(id), is_type_const } @@ -1355,8 +1344,7 @@ impl<'a> CrateMetadataRef<'a> { has_self: self.get_fn_has_self_parameter(tcx, id), }, DefKind::AssocTy => { - let data = if let Some(rpitit_info) = - self.root.tables.opt_rpitit_info.get(self.cdata, id) + let data = if let Some(rpitit_info) = self.root.tables.opt_rpitit_info.get(self, id) { ty::AssocTypeData::Rpitit(rpitit_info.decode((self, tcx))) } else { @@ -1366,33 +1354,31 @@ impl<'a> CrateMetadataRef<'a> { } _ => bug!("cannot get associated-item of `{:?}`", self.def_key(id)), }; - let container = - self.root.tables.assoc_container.get(self.cdata, id).unwrap().decode((self, tcx)); + let container = self.root.tables.assoc_container.get(self, id).unwrap().decode((self, tcx)); ty::AssocItem { kind, def_id: self.local_def_id(id), container } } - fn get_ctor(self, tcx: TyCtxt<'_>, node_id: DefIndex) -> Option<(CtorKind, DefId)> { + fn get_ctor(&self, tcx: TyCtxt<'_>, node_id: DefIndex) -> Option<(CtorKind, DefId)> { match self.def_kind(node_id) { DefKind::Struct | DefKind::Variant => { - let vdata = self - .root - .tables - .variant_data - .get(self.cdata, node_id) - .unwrap() - .decode((self, tcx)); + let vdata = + self.root.tables.variant_data.get(self, node_id).unwrap().decode((self, tcx)); vdata.ctor.map(|(kind, index)| (kind, self.local_def_id(index))) } _ => None, } } - fn get_item_attrs(self, tcx: TyCtxt<'_>, id: DefIndex) -> impl Iterator { + fn get_item_attrs( + &self, + tcx: TyCtxt<'_>, + id: DefIndex, + ) -> impl Iterator { self.root .tables .attributes - .get(self.cdata, id) + .get(self, id) .unwrap_or_else(|| { // Structure and variant constructors don't have any attributes encoded for them, // but we assume that someone passing a constructor ID actually wants to look at @@ -1403,14 +1389,14 @@ impl<'a> CrateMetadataRef<'a> { self.root .tables .attributes - .get(self.cdata, parent_id) + .get(self, parent_id) .expect("no encoded attributes for a structure or variant") }) .decode((self, tcx)) } fn get_inherent_implementations_for_type<'tcx>( - self, + &self, tcx: TyCtxt<'tcx>, id: DefIndex, ) -> &'tcx [DefId] { @@ -1418,26 +1404,26 @@ impl<'a> CrateMetadataRef<'a> { self.root .tables .inherent_impls - .get(self.cdata, id) + .get(self, id) .decode((self, tcx)) .map(|index| self.local_def_id(index)), ) } /// Decodes all traits in the crate (for rustdoc and rustc diagnostics). - fn get_traits(self, tcx: TyCtxt<'_>) -> impl Iterator { + fn get_traits(&self, tcx: TyCtxt<'_>) -> impl Iterator { self.root.traits.decode((self, tcx)).map(move |index| self.local_def_id(index)) } /// Decodes all trait impls in the crate (for rustdoc). - fn get_trait_impls(self, tcx: TyCtxt<'_>) -> impl Iterator { - self.cdata.trait_impls.values().flat_map(move |impls| { + fn get_trait_impls(&self, tcx: TyCtxt<'_>) -> impl Iterator { + self.trait_impls.values().flat_map(move |impls| { impls.decode((self, tcx)).map(move |(impl_index, _)| self.local_def_id(impl_index)) }) } - fn get_incoherent_impls<'tcx>(self, tcx: TyCtxt<'tcx>, simp: SimplifiedType) -> &'tcx [DefId] { - if let Some(impls) = self.cdata.incoherent_impls.get(&simp) { + fn get_incoherent_impls<'tcx>(&self, tcx: TyCtxt<'tcx>, simp: SimplifiedType) -> &'tcx [DefId] { + if let Some(impls) = self.incoherent_impls.get(&simp) { tcx.arena.alloc_from_iter(impls.decode((self, tcx)).map(|idx| self.local_def_id(idx))) } else { &[] @@ -1445,7 +1431,7 @@ impl<'a> CrateMetadataRef<'a> { } fn get_implementations_of_trait<'tcx>( - self, + &self, tcx: TyCtxt<'tcx>, trait_def_id: DefId, ) -> &'tcx [(DefId, Option)] { @@ -1471,25 +1457,25 @@ impl<'a> CrateMetadataRef<'a> { } } - fn get_native_libraries(self, tcx: TyCtxt<'_>) -> impl Iterator { + fn get_native_libraries(&self, tcx: TyCtxt<'_>) -> impl Iterator { self.root.native_libraries.decode((self, tcx)) } - fn get_proc_macro_quoted_span(self, tcx: TyCtxt<'_>, index: usize) -> Span { + fn get_proc_macro_quoted_span(&self, tcx: TyCtxt<'_>, index: usize) -> Span { self.root .tables .proc_macro_quoted_spans - .get(self.cdata, index) + .get(self, index) .unwrap_or_else(|| panic!("Missing proc macro quoted span: {index:?}")) .decode((self, tcx)) } - fn get_foreign_modules(self, tcx: TyCtxt<'_>) -> impl Iterator { + fn get_foreign_modules(&self, tcx: TyCtxt<'_>) -> impl Iterator { self.root.foreign_modules.decode((self, tcx)) } fn get_dylib_dependency_formats<'tcx>( - self, + &self, tcx: TyCtxt<'tcx>, ) -> &'tcx [(CrateNum, LinkagePreference)] { tcx.arena.alloc_from_iter( @@ -1503,22 +1489,22 @@ impl<'a> CrateMetadataRef<'a> { } fn get_externally_implementable_items( - self, + &self, tcx: TyCtxt<'_>, ) -> impl Iterator { self.root.externally_implementable_items.decode((self, tcx)) } - fn get_missing_lang_items<'tcx>(self, tcx: TyCtxt<'tcx>) -> &'tcx [LangItem] { + fn get_missing_lang_items<'tcx>(&self, tcx: TyCtxt<'tcx>) -> &'tcx [LangItem] { tcx.arena.alloc_from_iter(self.root.lang_items_missing.decode((self, tcx))) } - fn get_exportable_items(self, tcx: TyCtxt<'_>) -> impl Iterator { + fn get_exportable_items(&self, tcx: TyCtxt<'_>) -> impl Iterator { self.root.exportable_items.decode((self, tcx)).map(move |index| self.local_def_id(index)) } fn get_stable_order_of_exportable_impls( - self, + &self, tcx: TyCtxt<'_>, ) -> impl Iterator { self.root @@ -1528,30 +1514,25 @@ impl<'a> CrateMetadataRef<'a> { } fn exported_non_generic_symbols<'tcx>( - self, + &self, tcx: TyCtxt<'tcx>, ) -> &'tcx [(ExportedSymbol<'tcx>, SymbolExportInfo)] { tcx.arena.alloc_from_iter(self.root.exported_non_generic_symbols.decode((self, tcx))) } fn exported_generic_symbols<'tcx>( - self, + &self, tcx: TyCtxt<'tcx>, ) -> &'tcx [(ExportedSymbol<'tcx>, SymbolExportInfo)] { tcx.arena.alloc_from_iter(self.root.exported_generic_symbols.decode((self, tcx))) } - fn get_macro(self, tcx: TyCtxt<'_>, id: DefIndex) -> ast::MacroDef { + fn get_macro(&self, tcx: TyCtxt<'_>, id: DefIndex) -> ast::MacroDef { match self.def_kind(id) { DefKind::Macro(_) => { - let macro_rules = self.root.tables.is_macro_rules.get(self.cdata, id); - let body = self - .root - .tables - .macro_definition - .get(self.cdata, id) - .unwrap() - .decode((self, tcx)); + let macro_rules = self.root.tables.is_macro_rules.get(self, id); + let body = + self.root.tables.macro_definition.get(self, id).unwrap().decode((self, tcx)); ast::MacroDef { macro_rules, body: Box::new(body), eii_declaration: None } } _ => bug!(), @@ -1559,20 +1540,20 @@ impl<'a> CrateMetadataRef<'a> { } #[inline] - fn def_key(self, index: DefIndex) -> DefKey { + fn def_key(&self, index: DefIndex) -> DefKey { *self.def_key_cache.lock().entry(index).or_insert_with(|| { self.root.tables.def_keys.get(&self.blob, index).unwrap().decode(&self.blob) }) } // Returns the path leading to the thing with this `id`. - fn def_path(self, id: DefIndex) -> DefPath { + fn def_path(&self, id: DefIndex) -> DefPath { debug!("def_path(cnum={:?}, id={:?})", self.cnum, id); DefPath::make(self.cnum, id, |parent| self.def_key(parent)) } #[inline] - fn def_path_hash(self, index: DefIndex) -> DefPathHash { + fn def_path_hash(&self, index: DefIndex) -> DefPathHash { // This is a hack to workaround the fact that we can't easily encode/decode a Hash64 // into the FixedSizeEncoding, as Hash64 lacks a Default impl. A future refactor to // relax the Default restriction will likely fix this. @@ -1584,14 +1565,14 @@ impl<'a> CrateMetadataRef<'a> { } #[inline] - fn def_path_hash_to_def_index(self, hash: DefPathHash) -> Option { + fn def_path_hash_to_def_index(&self, hash: DefPathHash) -> Option { self.def_path_hash_map.def_path_hash_to_def_index(&hash) } - fn expn_hash_to_expn_id(self, tcx: TyCtxt<'_>, index_guess: u32, hash: ExpnHash) -> ExpnId { + fn expn_hash_to_expn_id(&self, tcx: TyCtxt<'_>, index_guess: u32, hash: ExpnHash) -> ExpnId { let index_guess = ExpnIndex::from_u32(index_guess); let old_hash = - self.root.expn_hashes.get(self.cdata, index_guess).map(|lazy| lazy.decode((self, tcx))); + self.root.expn_hashes.get(self, index_guess).map(|lazy| lazy.decode((self, tcx))); let index = if old_hash == Some(hash) { // Fast path: the expn and its index is unchanged from the @@ -1602,13 +1583,13 @@ impl<'a> CrateMetadataRef<'a> { // Slow path: We need to find out the new `DefIndex` of the provided // `DefPathHash`, if its still exists. This requires decoding every `DefPathHash` // stored in this crate. - let map = self.cdata.expn_hash_map.get_or_init(|| { + let map = self.expn_hash_map.get_or_init(|| { let end_id = self.root.expn_hashes.size() as u32; let mut map = UnhashMap::with_capacity_and_hasher(end_id as usize, Default::default()); for i in 0..end_id { let i = ExpnIndex::from_u32(i); - if let Some(hash) = self.root.expn_hashes.get(self.cdata, i) { + if let Some(hash) = self.root.expn_hashes.get(self, i) { map.insert(hash.decode((self, tcx)), i); } } @@ -1617,7 +1598,7 @@ impl<'a> CrateMetadataRef<'a> { map[&hash] }; - let data = self.root.expn_data.get(self.cdata, index).unwrap().decode((self, tcx)); + let data = self.root.expn_data.get(self, index).unwrap().decode((self, tcx)); rustc_span::hygiene::register_expn_id(self.cnum, index, data, hash) } @@ -1646,7 +1627,7 @@ impl<'a> CrateMetadataRef<'a> { /// /// Proc macro crates don't currently export spans, so this function does not have /// to work for them. - fn imported_source_file(self, tcx: TyCtxt<'_>, source_file_index: u32) -> ImportedSourceFile { + fn imported_source_file(&self, tcx: TyCtxt<'_>, source_file_index: u32) -> ImportedSourceFile { fn filter<'a>( tcx: TyCtxt<'_>, real_source_base_dir: &Option, @@ -1745,7 +1726,7 @@ impl<'a> CrateMetadataRef<'a> { } }; - let mut import_info = self.cdata.source_map_import_info.lock(); + let mut import_info = self.source_map_import_info.lock(); for _ in import_info.len()..=(source_file_index as usize) { import_info.push(None); } @@ -1754,7 +1735,7 @@ impl<'a> CrateMetadataRef<'a> { let source_file_to_import = self .root .source_map - .get(self.cdata, source_file_index) + .get(self, source_file_index) .expect("missing source file") .decode((self, tcx)); @@ -1855,32 +1836,32 @@ impl<'a> CrateMetadataRef<'a> { .clone() } - fn get_attr_flags(self, index: DefIndex) -> AttrFlags { - self.root.tables.attr_flags.get(self.cdata, index) + fn get_attr_flags(&self, index: DefIndex) -> AttrFlags { + self.root.tables.attr_flags.get(self, index) } - fn get_intrinsic(self, tcx: TyCtxt<'_>, index: DefIndex) -> Option { - self.root.tables.intrinsic.get(self.cdata, index).map(|d| d.decode((self, tcx))) + fn get_intrinsic(&self, tcx: TyCtxt<'_>, index: DefIndex) -> Option { + self.root.tables.intrinsic.get(self, index).map(|d| d.decode((self, tcx))) } - fn get_doc_link_resolutions(self, tcx: TyCtxt<'_>, index: DefIndex) -> DocLinkResMap { + fn get_doc_link_resolutions(&self, tcx: TyCtxt<'_>, index: DefIndex) -> DocLinkResMap { self.root .tables .doc_link_resolutions - .get(self.cdata, index) + .get(self, index) .expect("no resolutions for a doc link") .decode((self, tcx)) } fn get_doc_link_traits_in_scope( - self, + &self, tcx: TyCtxt<'_>, index: DefIndex, ) -> impl Iterator { self.root .tables .doc_link_traits_in_scope - .get(self.cdata, index) + .get(self, index) .expect("no traits in scope for a doc link") .decode((self, tcx)) } @@ -1889,7 +1870,6 @@ impl<'a> CrateMetadataRef<'a> { impl CrateMetadata { pub(crate) fn new( tcx: TyCtxt<'_>, - cstore: &CStore, blob: MetadataBlob, root: CrateRoot, raw_proc_macros: Option<&'static [ProcMacro]>, @@ -1934,14 +1914,12 @@ impl CrateMetadata { def_key_cache: Default::default(), }; - // Need `CrateMetadataRef` to decode `DefId`s in simplified types. - let cref = CrateMetadataRef { cdata: &cdata, cstore }; cdata.incoherent_impls = cdata .root .incoherent_impls - .decode((cref, tcx)) + .decode((&cdata, tcx)) .map(|incoherent_impls| { - (incoherent_impls.self_ty.decode((cref, tcx)), incoherent_impls.impls) + (incoherent_impls.self_ty.decode((&cdata, tcx)), incoherent_impls.impls) }) .collect(); @@ -2041,13 +2019,10 @@ impl CrateMetadata { &self, tcx: TyCtxt<'_>, krate: CrateNum, - cstore: &CStore, ) -> impl Iterator { gen move { for def_id in self.root.proc_macro_data.as_ref().into_iter().flat_map(move |data| { - data.macros - .decode((CrateMetadataRef { cdata: self, cstore }, tcx)) - .map(move |index| DefId { index, krate }) + data.macros.decode((self, tcx)).map(move |index| DefId { index, krate }) }) { yield def_id; } diff --git a/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs b/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs index 3e63e953e4469..a00fb59963ac2 100644 --- a/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs +++ b/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs @@ -100,7 +100,7 @@ macro_rules! provide_one { .root .tables .$name - .get($cdata.cdata, $def_id.index) + .get($cdata, $def_id.index) .map(|lazy| lazy.decode(($cdata, $tcx))) .process_decoded($tcx, || panic!("{:?} does not have a {:?}", $def_id, stringify!($name))) } @@ -109,7 +109,7 @@ macro_rules! provide_one { ($tcx:ident, $def_id:ident, $other:ident, $cdata:ident, $name:ident => { table_defaulted_array }) => { provide_one! { $tcx, $def_id, $other, $cdata, $name => { - let lazy = $cdata.root.tables.$name.get($cdata.cdata, $def_id.index); + let lazy = $cdata.root.tables.$name.get($cdata, $def_id.index); let value = if lazy.is_default() { &[] as &[_] } else { @@ -127,7 +127,7 @@ macro_rules! provide_one { .root .tables .$name - .get($cdata.cdata, $def_id.index) + .get($cdata, $def_id.index) .process_decoded($tcx, || panic!("{:?} does not have a {:?}", $def_id, stringify!($name))) } } @@ -259,7 +259,7 @@ provide! { tcx, def_id, other, cdata, .root .tables .coerce_unsized_info - .get(cdata.cdata, def_id.index) + .get(cdata, def_id.index) .map(|lazy| lazy.decode((cdata, tcx))) .process_decoded(tcx, || panic!("{def_id:?} does not have coerce_unsized_info"))) } mir_const_qualif => { table } @@ -275,7 +275,7 @@ provide! { tcx, def_id, other, cdata, .root .tables .eval_static_initializer - .get(cdata.cdata, def_id.index) + .get(cdata, def_id.index) .map(|lazy| lazy.decode((cdata, tcx))) .unwrap_or_else(|| panic!("{def_id:?} does not have eval_static_initializer"))) } @@ -288,7 +288,7 @@ provide! { tcx, def_id, other, cdata, .root .tables .deduced_param_attrs - .get(cdata.cdata, def_id.index) + .get(cdata, def_id.index) .map(|lazy| { &*tcx.arena.alloc_from_iter(lazy.decode((cdata, tcx))) }) @@ -301,7 +301,7 @@ provide! { tcx, def_id, other, cdata, .root .tables .trait_impl_trait_tys - .get(cdata.cdata, def_id.index) + .get(cdata, def_id.index) .map(|lazy| lazy.decode((cdata, tcx))) .process_decoded(tcx, || panic!("{def_id:?} does not have trait_impl_trait_tys"))) } @@ -399,7 +399,9 @@ provide! { tcx, def_id, other, cdata, debugger_visualizers => { cdata.get_debugger_visualizers(tcx) } exportable_items => { tcx.arena.alloc_from_iter(cdata.get_exportable_items(tcx)) } - stable_order_of_exportable_impls => { tcx.arena.alloc(cdata.get_stable_order_of_exportable_impls(tcx).collect()) } + stable_order_of_exportable_impls => { + tcx.arena.alloc(cdata.get_stable_order_of_exportable_impls(tcx).collect()) + } exported_non_generic_symbols => { cdata.exported_non_generic_symbols(tcx) } exported_generic_symbols => { cdata.exported_generic_symbols(tcx) } @@ -590,16 +592,16 @@ impl CStore { let sess = tcx.sess; let _prof_timer = sess.prof.generic_activity("metadata_load_macro"); - let data = self.get_crate_data(id.krate); - if data.root.is_proc_macro_crate() { - LoadedMacro::ProcMacro(data.load_proc_macro(tcx, id.index)) + let cdata = self.get_crate_data(id.krate); + if cdata.root.is_proc_macro_crate() { + LoadedMacro::ProcMacro(cdata.load_proc_macro(tcx, id.index)) } else { LoadedMacro::MacroDef { - def: data.get_macro(tcx, id.index), - ident: data.item_ident(tcx, id.index), - attrs: data.get_item_attrs(tcx, id.index).collect(), - span: data.get_span(tcx, id.index), - edition: data.root.edition, + def: cdata.get_macro(tcx, id.index), + ident: cdata.item_ident(tcx, id.index), + attrs: cdata.get_item_attrs(tcx, id.index).collect(), + span: cdata.get_span(tcx, id.index), + edition: cdata.root.edition, } } } @@ -641,10 +643,10 @@ impl CStore { } pub fn set_used_recursively(&mut self, cnum: CrateNum) { - let cmeta = self.get_crate_data_mut(cnum); - if !cmeta.used { - cmeta.used = true; - let cnum_map = mem::take(&mut cmeta.cnum_map); + let cdata = self.get_crate_data_mut(cnum); + if !cdata.used { + cdata.used = true; + let cnum_map = mem::take(&mut cdata.cnum_map); for &dep_cnum in cnum_map.iter() { self.set_used_recursively(dep_cnum); } @@ -676,11 +678,11 @@ impl CStore { cnum: CrateNum, extern_crate: ExternCrate, ) { - let cmeta = self.get_crate_data_mut(cnum); - if cmeta.update_extern_crate_diagnostics(extern_crate) { + let cdata = self.get_crate_data_mut(cnum); + if cdata.update_extern_crate_diagnostics(extern_crate) { // Propagate the extern crate info to dependencies if it was updated. let extern_crate = ExternCrate { dependency_of: cnum, ..extern_crate }; - let cnum_map = mem::take(&mut cmeta.cnum_map); + let cnum_map = mem::take(&mut cdata.cnum_map); for &dep_cnum in cnum_map.iter() { self.update_transitive_extern_crate_diagnostics(dep_cnum, extern_crate); } diff --git a/compiler/rustc_metadata/src/rmeta/mod.rs b/compiler/rustc_metadata/src/rmeta/mod.rs index 781d3c6d18372..c7b2eaa15ebfb 100644 --- a/compiler/rustc_metadata/src/rmeta/mod.rs +++ b/compiler/rustc_metadata/src/rmeta/mod.rs @@ -45,7 +45,6 @@ use rustc_span::{self, ExpnData, ExpnHash, ExpnId, Ident, Span, Symbol}; use rustc_target::spec::{PanicStrategy, TargetTuple}; use table::TableBuilder; -use crate::creader::CrateMetadataRef; use crate::eii::EiiMapEncodedKeyValue; mod decoder; @@ -317,13 +316,9 @@ impl From for RawDefId { impl RawDefId { /// This exists so that `provide_one!` is happy - fn decode(self, meta: (CrateMetadataRef<'_>, TyCtxt<'_>)) -> DefId { - self.decode_from_cdata(meta.0) - } - - fn decode_from_cdata(self, cdata: CrateMetadataRef<'_>) -> DefId { + fn decode(self, meta: (&CrateMetadata, TyCtxt<'_>)) -> DefId { let krate = CrateNum::from_u32(self.krate); - let krate = cdata.map_encoded_cnum_to_current(krate); + let krate = meta.0.map_encoded_cnum_to_current(krate); DefId { krate, index: DefIndex::from_u32(self.index) } } } From 70fe8a6dc4a903bae3f630ac1dcc5cd27faa9e02 Mon Sep 17 00:00:00 2001 From: Sidney Cammeresi Date: Wed, 22 Apr 2026 21:21:55 -0700 Subject: [PATCH 154/183] Add `Sender` diagnostic item for `std::sync::mpsc::Sender` Similar to the existing `Receiver` item, it will be used in Clippy to detect uses of `is_disconnected` that are racy. --- library/std/src/sync/mpsc.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/library/std/src/sync/mpsc.rs b/library/std/src/sync/mpsc.rs index a1c49bb83010c..460ad02c67d2c 100644 --- a/library/std/src/sync/mpsc.rs +++ b/library/std/src/sync/mpsc.rs @@ -330,6 +330,7 @@ pub struct IntoIter { /// assert_eq!(3, msg + msg2); /// ``` #[stable(feature = "rust1", since = "1.0.0")] +#[cfg_attr(not(test), rustc_diagnostic_item = "MpscSender")] pub struct Sender { inner: mpmc::Sender, } From 0a5785734c9880b775939fc62f53376ad8249d39 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Thu, 23 Apr 2026 22:22:17 +0000 Subject: [PATCH 155/183] c-b: Ensure check-cfg is set for all targets Emscripten and OpenBSD exit out of the build script early. Since 02014b06c1a3 ("c-b: Turn `mem-unaligned` from a feature to a cfg"), this meant that the exit happened before all `rustc-check-cfg`s had been emitted. Rework the logic so these only skip the C build rather than the rest of configuration. --- library/compiler-builtins/ci/miri.sh | 2 +- .../compiler-builtins/build.rs | 66 +++++++++---------- 2 files changed, 32 insertions(+), 36 deletions(-) diff --git a/library/compiler-builtins/ci/miri.sh b/library/compiler-builtins/ci/miri.sh index 90b64934db0b5..2751bf0dc49e1 100755 --- a/library/compiler-builtins/ci/miri.sh +++ b/library/compiler-builtins/ci/miri.sh @@ -5,7 +5,7 @@ set -eux # compatible with Stacked Borrows. export MIRIFLAGS="-Zmiri-tree-borrows" -# One target that sets `mem-unaligned` and one that does not, +# One target that sets `mem_unaligned` and one that does not, # and a big-endian target. targets=( x86_64-unknown-linux-gnu diff --git a/library/compiler-builtins/compiler-builtins/build.rs b/library/compiler-builtins/compiler-builtins/build.rs index d8019277d3ff4..748699c4d3e17 100644 --- a/library/compiler-builtins/compiler-builtins/build.rs +++ b/library/compiler-builtins/compiler-builtins/build.rs @@ -7,6 +7,7 @@ use configure::{Config, Library, set_cfg}; fn main() { let cfg = Config::from_env(Library::CompilerBuiltins); + let llvm_target = &cfg.target_triple_split; // Work around building as part of `builtins-shim`: if only `build.rs` is used, Cargo always // considers the build dirty because `builtins-shim/build.rs` does not exist. If only @@ -25,21 +26,6 @@ fn main() { let cwd = env::current_dir().unwrap(); println!("cargo:compiler-rt={}", cwd.join("compiler-rt").display()); - println!("cargo::rustc-check-cfg=cfg(kernel_user_helpers)"); - println!("cargo::rustc-check-cfg=cfg(feature, values(\"mem-unaligned\"))"); - - // Emscripten's runtime includes all the builtins - if cfg.target_os == "emscripten" { - return; - } - - // OpenBSD provides compiler_rt by default, use it instead of rebuilding it from source - if cfg.target_os == "openbsd" { - println!("cargo:rustc-link-search=native=/usr/lib"); - println!("cargo:rustc-link-lib=compiler_rt"); - return; - } - // Forcibly enable memory intrinsics on wasm & SGX as we don't have a libc to // provide them. if (cfg.target_triple.contains("wasm") && !cfg.target_triple.contains("wasi")) @@ -59,25 +45,6 @@ fn main() { || cfg.target_arch.contains("bpf"); set_cfg("mem_unaligned", mem_unaligned); - // NOTE we are going to assume that llvm-target, what determines our codegen option, matches the - // target triple. This is usually correct for our built-in targets but can break in presence of - // custom targets, which can have arbitrary names. - let llvm_target = cfg.target_triple.split('-').collect::>(); - - // Build missing intrinsics from compiler-rt C source code. If we're - // mangling names though we assume that we're also in test mode so we don't - // build anything and we rely on the upstream implementation of compiler-rt - // functions - if cfg!(feature = "unmangled-names") && cfg!(feature = "c") { - // Don't use a C compiler for these targets: - // - // * nvptx - everything is bitcode, not compatible with mixed C/Rust - if !cfg.target_arch.contains("nvptx") { - #[cfg(feature = "c")] - c::compile(&llvm_target, &cfg); - } - } - // Only emit the ARM Linux atomic emulation on pre-ARMv6 architectures. This // includes the old androideabi. It is deprecated but it is available as a // rustc target (arm-linux-androideabi). @@ -85,6 +52,34 @@ fn main() { || llvm_target[0] == "armv5te" || cfg.target_triple == "arm-linux-androideabi"; set_cfg("kernel_user_helpers", kernel_user_helpers); + + let mut maybe_build_c = true; + + // Emscripten's runtime includes all the builtins + if cfg.target_os == "emscripten" { + maybe_build_c = false; + } + + // OpenBSD provides compiler_rt by default, use it instead of rebuilding it from source + if cfg.target_os == "openbsd" { + println!("cargo:rustc-link-search=native=/usr/lib"); + println!("cargo:rustc-link-lib=compiler_rt"); + maybe_build_c = false; + } + + // Everything is LLVM bitcode, not compatible with mixed C/Rust + if cfg.target_arch.contains("nvptx") { + maybe_build_c = false; + } + + // Build missing intrinsics from compiler-rt C source code. If we're + // mangling names though we assume that we're also in test mode so we don't + // build anything and we rely on the upstream implementation of compiler-rt + // functions + if cfg!(feature = "unmangled-names") && cfg!(feature = "c") && maybe_build_c { + #[cfg(feature = "c")] + c::compile(&cfg); + } } /// Emit directives for features we expect to support that aren't in `Cargo.toml`. @@ -198,7 +193,8 @@ mod c { } /// Compile intrinsics from the compiler-rt C source code - pub fn compile(llvm_target: &[&str], cfg: &Config) { + pub fn compile(cfg: &Config) { + let llvm_target = &cfg.target_triple_split; let mut consider_float_intrinsics = true; let build = &mut cc::Build::new(); From bcb1af095ed973da0f9dfb3c5f759707f0e66113 Mon Sep 17 00:00:00 2001 From: Zalathar Date: Wed, 22 Apr 2026 14:11:19 +1000 Subject: [PATCH 156/183] Forbid `*-pass` and `*-fail` directives in tests/crashes Crash tests are always expected to crash during compilation, so there is no sensible meaning for specifying a pass/fail expectation in a crash test. --- src/doc/rustc-dev-guide/src/tests/directives.md | 16 ++++++++-------- src/tools/compiletest/src/directives.rs | 4 +--- src/tools/compiletest/src/runtest/crashes.rs | 5 ++--- 3 files changed, 11 insertions(+), 14 deletions(-) diff --git a/src/doc/rustc-dev-guide/src/tests/directives.md b/src/doc/rustc-dev-guide/src/tests/directives.md index d536d324cb2bf..38450d991d05a 100644 --- a/src/doc/rustc-dev-guide/src/tests/directives.md +++ b/src/doc/rustc-dev-guide/src/tests/directives.md @@ -70,17 +70,17 @@ See [Controlling pass/fail expectations](ui.md#controlling-passfail-expectations | Directive | Explanation | Supported test suites | Possible values | |-----------------------------|---------------------------------------------|-------------------------------------------|-----------------| -| `check-pass` | Building (no codegen) should pass | `ui`, `crashes` | N/A | -| `check-fail` | Building (no codegen) should fail | `ui`, `crashes` | N/A | -| `build-pass` | Building should pass | `ui`, `crashes`, `codegen` | N/A | -| `build-fail` | Building should fail | `ui`, `crashes` | N/A | -| `run-pass` | Program must exit with code `0` | `ui`, `crashes` | N/A | -| `run-fail` | Program must exit with code `1..=127` | `ui`, `crashes` | N/A | +| `check-pass` | Building (no codegen) should pass | `ui` | N/A | +| `check-fail` | Building (no codegen) should fail | `ui` | N/A | +| `build-pass` | Building should pass | `ui` | N/A | +| `build-fail` | Building should fail | `ui` | N/A | +| `run-pass` | Program must exit with code `0` | `ui` | N/A | +| `run-fail` | Program must exit with code `1..=127` | `ui` | N/A | | `run-crash` | Program must crash | `ui` | N/A | | `run-fail-or-crash` | Program must `run-fail` or `run-crash` | `ui` | N/A | -| `ignore-pass` | Ignore `--pass` flag | `ui`, `crashes`, `codegen`, `incremental` | N/A | +| `ignore-pass` | Ignore `--pass` flag | `ui` | N/A | | `dont-check-failure-status` | Don't check exact failure status (i.e. `1`) | `ui`, `incremental` | N/A | -| `failure-status` | On failure, the compiler must exit with this status code. To expect an ICE, use `//@ failure-status: 101`. | `ui`, `crashes`, `incremental` | Any `u16` | +| `failure-status` | On failure, the compiler must exit with this status code. To expect an ICE, use `//@ failure-status: 101`. | `ui`, `incremental` | Any `u16` | | `should-fail` | Compiletest self-test | All | N/A | ### Controlling output snapshots and normalizations diff --git a/src/tools/compiletest/src/directives.rs b/src/tools/compiletest/src/directives.rs index d87cb915b07b8..0575285af7a43 100644 --- a/src/tools/compiletest/src/directives.rs +++ b/src/tools/compiletest/src/directives.rs @@ -408,8 +408,7 @@ impl TestProps { fn update_fail_mode(&mut self, ln: &DirectiveLine<'_>, config: &Config) { let check_ui = |mode: &str| { - // Mode::Crashes may need build-fail in order to trigger llvm errors or stack overflows - if config.mode != TestMode::Ui && config.mode != TestMode::Crashes { + if config.mode != TestMode::Ui { panic!("`{}-fail` directive is only supported in UI tests", mode); } }; @@ -441,7 +440,6 @@ impl TestProps { fn update_pass_mode(&mut self, ln: &DirectiveLine<'_>, config: &Config) { let check_no_run = |s| match (config.mode, s) { (TestMode::Ui, _) => (), - (TestMode::Crashes, _) => (), (mode, _) => panic!("`{s}` directive is not supported in `{mode}` tests"), }; let pass_mode = if config.parse_name_directive(ln, "check-pass") { diff --git a/src/tools/compiletest/src/runtest/crashes.rs b/src/tools/compiletest/src/runtest/crashes.rs index 0aae7eaa39cd5..210ab4dd05a71 100644 --- a/src/tools/compiletest/src/runtest/crashes.rs +++ b/src/tools/compiletest/src/runtest/crashes.rs @@ -1,9 +1,8 @@ -use super::{TestCx, WillExecute}; +use super::{Emit, TestCx, WillExecute}; impl TestCx<'_> { pub(super) fn run_crash_test(&self) { - let pm = self.pass_mode(); - let proc_res = self.compile_test(WillExecute::No, self.should_emit_metadata(pm)); + let proc_res = self.compile_test(WillExecute::No, Emit::None); if std::env::var("COMPILETEST_VERBOSE_CRASHES").is_ok() { writeln!(self.stderr, "{}", proc_res.status); From 4b1f3926deb3d6b508ef3dc3985ff0fe417e417b Mon Sep 17 00:00:00 2001 From: Ben Kimock Date: Fri, 24 Apr 2026 03:04:03 +0000 Subject: [PATCH 157/183] Avoid query cycles in DataflowConstProp * Avoid query cycles in DataflowConstProp * Add -Zmir-opt-level=0 to the test --- .../rustc_mir_transform/src/dataflow_const_prop.rs | 5 +++++ tests/ui/dataflow_const_prop/recursive-async.rs | 11 +++++++++++ 2 files changed, 16 insertions(+) create mode 100644 tests/ui/dataflow_const_prop/recursive-async.rs diff --git a/compiler/rustc_mir_transform/src/dataflow_const_prop.rs b/compiler/rustc_mir_transform/src/dataflow_const_prop.rs index 122429276e3c5..a2df3dcb85acf 100644 --- a/compiler/rustc_mir_transform/src/dataflow_const_prop.rs +++ b/compiler/rustc_mir_transform/src/dataflow_const_prop.rs @@ -41,6 +41,11 @@ impl<'tcx> crate::MirPass<'tcx> for DataflowConstProp { #[instrument(skip_all level = "debug")] fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { + // Avoid query cycles from coroutines. + if body.coroutine.is_some() { + return; + } + debug!(def_id = ?body.source.def_id()); if tcx.sess.mir_opt_level() < 4 && body.basic_blocks.len() > BLOCK_LIMIT { debug!("aborted dataflow const prop due too many basic blocks"); diff --git a/tests/ui/dataflow_const_prop/recursive-async.rs b/tests/ui/dataflow_const_prop/recursive-async.rs new file mode 100644 index 0000000000000..f2c194c6ca3ff --- /dev/null +++ b/tests/ui/dataflow_const_prop/recursive-async.rs @@ -0,0 +1,11 @@ +//! Ensure DataflowConstProp doesn't cause an error with async recursion as in #155376. + +//@ edition:2018 +//@ check-pass +//@ compile-flags: -Zmir-opt-level=0 -Zmir-enable-passes=+DataflowConstProp --crate-type=lib + +pub async fn foo(n: usize) { + if n > 0 { + Box::pin(foo(n - 1)).await; + } +} From 7ba9478184436b9627178b61071d2b9ff9acb81c Mon Sep 17 00:00:00 2001 From: Zac Harrold Date: Thu, 23 Apr 2026 21:41:59 +1000 Subject: [PATCH 158/183] Implement `Read`/`Write`/`Seek` for `Arc` Added a marker trait `IoHandle` which can be used by the standard library to opt-in types to a blanket implementation of the various IO traits on `Arc` where `&T: IoTrait` for some `IoTrait`. The marker is required to avoid types like `Arc<[u8]>` being included, since they don't have interior mutability and would not give expected results. --- library/std/src/fs.rs | 54 +--------------- library/std/src/io/impls.rs | 120 ++++++++++++++++++++++++++++++++++++ library/std/src/io/mod.rs | 15 +++++ 3 files changed, 136 insertions(+), 53 deletions(-) diff --git a/library/std/src/fs.rs b/library/std/src/fs.rs index c75f005f18021..fab695c1c5e1f 100644 --- a/library/std/src/fs.rs +++ b/library/std/src/fs.rs @@ -45,7 +45,6 @@ use crate::ffi::OsString; use crate::io::{self, BorrowedCursor, IoSlice, IoSliceMut, Read, Seek, SeekFrom, Write}; use crate::path::{Path, PathBuf}; use crate::sealed::Sealed; -use crate::sync::Arc; use crate::sys::{AsInner, AsInnerMut, FromInner, IntoInner, fs as fs_imp}; use crate::time::SystemTime; use crate::{error, fmt}; @@ -1541,58 +1540,7 @@ impl Seek for File { (&*self).stream_position() } } - -#[stable(feature = "io_traits_arc", since = "1.73.0")] -impl Read for Arc { - fn read(&mut self, buf: &mut [u8]) -> io::Result { - (&**self).read(buf) - } - fn read_vectored(&mut self, bufs: &mut [IoSliceMut<'_>]) -> io::Result { - (&**self).read_vectored(bufs) - } - fn read_buf(&mut self, cursor: BorrowedCursor<'_>) -> io::Result<()> { - (&**self).read_buf(cursor) - } - #[inline] - fn is_read_vectored(&self) -> bool { - (&**self).is_read_vectored() - } - fn read_to_end(&mut self, buf: &mut Vec) -> io::Result { - (&**self).read_to_end(buf) - } - fn read_to_string(&mut self, buf: &mut String) -> io::Result { - (&**self).read_to_string(buf) - } -} -#[stable(feature = "io_traits_arc", since = "1.73.0")] -impl Write for Arc { - fn write(&mut self, buf: &[u8]) -> io::Result { - (&**self).write(buf) - } - fn write_vectored(&mut self, bufs: &[IoSlice<'_>]) -> io::Result { - (&**self).write_vectored(bufs) - } - #[inline] - fn is_write_vectored(&self) -> bool { - (&**self).is_write_vectored() - } - #[inline] - fn flush(&mut self) -> io::Result<()> { - (&**self).flush() - } -} -#[stable(feature = "io_traits_arc", since = "1.73.0")] -impl Seek for Arc { - fn seek(&mut self, pos: SeekFrom) -> io::Result { - (&**self).seek(pos) - } - fn stream_len(&mut self) -> io::Result { - (&**self).stream_len() - } - fn stream_position(&mut self) -> io::Result { - (&**self).stream_position() - } -} +impl crate::io::IoHandle for File {} impl Dir { /// Attempts to open a directory at `path` in read-only mode. diff --git a/library/std/src/io/impls.rs b/library/std/src/io/impls.rs index d0245f3d4984c..f0b7764b4cc5e 100644 --- a/library/std/src/io/impls.rs +++ b/library/std/src/io/impls.rs @@ -4,6 +4,7 @@ mod tests; use crate::alloc::Allocator; use crate::collections::VecDeque; use crate::io::{self, BorrowedCursor, BufRead, IoSlice, IoSliceMut, Read, Seek, SeekFrom, Write}; +use crate::sync::Arc; use crate::{cmp, fmt, mem, str}; // ============================================================================= @@ -715,3 +716,122 @@ impl<'a> io::Write for core::io::BorrowedCursor<'a> { Ok(()) } } + +#[stable(feature = "io_traits_arc", since = "1.73.0")] +impl Read for Arc +where + for<'a> &'a R: Read, + R: crate::io::IoHandle, +{ + #[inline] + fn read(&mut self, buf: &mut [u8]) -> io::Result { + (&**self).read(buf) + } + + #[inline] + fn read_buf(&mut self, cursor: BorrowedCursor<'_>) -> io::Result<()> { + (&**self).read_buf(cursor) + } + + #[inline] + fn read_vectored(&mut self, bufs: &mut [IoSliceMut<'_>]) -> io::Result { + (&**self).read_vectored(bufs) + } + + #[inline] + fn is_read_vectored(&self) -> bool { + (&**self).is_read_vectored() + } + + #[inline] + fn read_to_end(&mut self, buf: &mut Vec) -> io::Result { + (&**self).read_to_end(buf) + } + + #[inline] + fn read_to_string(&mut self, buf: &mut String) -> io::Result { + (&**self).read_to_string(buf) + } + + #[inline] + fn read_exact(&mut self, buf: &mut [u8]) -> io::Result<()> { + (&**self).read_exact(buf) + } + + #[inline] + fn read_buf_exact(&mut self, cursor: BorrowedCursor<'_>) -> io::Result<()> { + (&**self).read_buf_exact(cursor) + } +} +#[stable(feature = "io_traits_arc", since = "1.73.0")] +impl Write for Arc +where + for<'a> &'a W: Write, + W: crate::io::IoHandle, +{ + #[inline] + fn write(&mut self, buf: &[u8]) -> io::Result { + (&**self).write(buf) + } + + #[inline] + fn write_vectored(&mut self, bufs: &[IoSlice<'_>]) -> io::Result { + (&**self).write_vectored(bufs) + } + + #[inline] + fn is_write_vectored(&self) -> bool { + (&**self).is_write_vectored() + } + + #[inline] + fn flush(&mut self) -> io::Result<()> { + (&**self).flush() + } + + #[inline] + fn write_all(&mut self, buf: &[u8]) -> io::Result<()> { + (&**self).write_all(buf) + } + + #[inline] + fn write_all_vectored(&mut self, bufs: &mut [IoSlice<'_>]) -> io::Result<()> { + (&**self).write_all_vectored(bufs) + } + + #[inline] + fn write_fmt(&mut self, fmt: fmt::Arguments<'_>) -> io::Result<()> { + (&**self).write_fmt(fmt) + } +} +#[stable(feature = "io_traits_arc", since = "1.73.0")] +impl Seek for Arc +where + for<'a> &'a S: Seek, + S: crate::io::IoHandle, +{ + #[inline] + fn seek(&mut self, pos: SeekFrom) -> io::Result { + (&**self).seek(pos) + } + + #[inline] + fn rewind(&mut self) -> io::Result<()> { + (&**self).rewind() + } + + #[inline] + fn stream_len(&mut self) -> io::Result { + (&**self).stream_len() + } + + #[inline] + fn stream_position(&mut self) -> io::Result { + (&**self).stream_position() + } + + #[inline] + fn seek_relative(&mut self, offset: i64) -> io::Result<()> { + (&**self).seek_relative(offset) + } +} diff --git a/library/std/src/io/mod.rs b/library/std/src/io/mod.rs index 1166ba8baf430..934d4bd684034 100644 --- a/library/std/src/io/mod.rs +++ b/library/std/src/io/mod.rs @@ -2226,6 +2226,21 @@ pub enum SeekFrom { Current(#[stable(feature = "rust1", since = "1.0.0")] i64), } +/// Marks that a type `T` can have IO traits such as [`Seek`], [`Write`], etc. automatically +/// implemented for handle types like [`Arc`][arc] as well. +/// +/// This trait should only be implemented for types where `<&T as Trait>::method(&mut &value, ..)` +/// would be identical to `::method(&mut value, ..)`. +/// +/// [`File`][file] passes this test, as operations on `&File` and `File` both affect +/// the same underlying file. +/// `[u8]` fails, because any modification to `&mut &[u8]` would only affect a temporary +/// and be lost after the method has been called. +/// +/// [file]: crate::fs::File +/// [arc]: crate::sync::Arc +pub(crate) trait IoHandle {} + fn read_until(r: &mut R, delim: u8, buf: &mut Vec) -> Result { let mut read = 0; loop { From 7f2a98d1fc32aca890c44f1b62e815b09284f9f9 Mon Sep 17 00:00:00 2001 From: aerooneqq Date: Fri, 24 Apr 2026 09:59:20 +0300 Subject: [PATCH 159/183] Rename Self generic param to This in recursive delegations --- compiler/rustc_ast_lowering/src/delegation.rs | 15 ++-- .../src/delegation/generics.rs | 83 +++++++++++++++---- tests/pretty/delegation-self-rename.pp | 55 ++++++++++++ tests/pretty/delegation-self-rename.rs | 32 +++++++ tests/ui/delegation/generics/self-rename.rs | 45 ++++++++++ .../generics/synth-params-ice-154780.rs | 71 +++++++++------- 6 files changed, 242 insertions(+), 59 deletions(-) create mode 100644 tests/pretty/delegation-self-rename.pp create mode 100644 tests/pretty/delegation-self-rename.rs create mode 100644 tests/ui/delegation/generics/self-rename.rs diff --git a/compiler/rustc_ast_lowering/src/delegation.rs b/compiler/rustc_ast_lowering/src/delegation.rs index 593eac2df4893..3a5b6ad608aa2 100644 --- a/compiler/rustc_ast_lowering/src/delegation.rs +++ b/compiler/rustc_ast_lowering/src/delegation.rs @@ -508,7 +508,7 @@ impl<'hir, R: ResolverAstLoweringExt<'hir>> LoweringContext<'_, 'hir, R> { // FIXME(fn_delegation): proper support for parent generics propagation // in method call scenario. - let segment = self.process_segment(span, &segment, &mut generics.child, false); + let segment = self.process_segment(span, &segment, &mut generics.child); let segment = self.arena.alloc(segment); self.arena.alloc(hir::Expr { @@ -534,14 +534,10 @@ impl<'hir, R: ResolverAstLoweringExt<'hir>> LoweringContext<'_, 'hir, R> { new_path.segments = self.arena.alloc_from_iter( new_path.segments.iter().enumerate().map(|(idx, segment)| { - let mut process_segment = |result, add_lifetimes| { - self.process_segment(span, segment, result, add_lifetimes) - }; - if idx + 2 == len { - process_segment(&mut generics.parent, true) + self.process_segment(span, segment, &mut generics.parent) } else if idx + 1 == len { - process_segment(&mut generics.child, false) + self.process_segment(span, segment, &mut generics.child) } else { segment.clone() } @@ -551,7 +547,7 @@ impl<'hir, R: ResolverAstLoweringExt<'hir>> LoweringContext<'_, 'hir, R> { hir::QPath::Resolved(ty, self.arena.alloc(new_path)) } hir::QPath::TypeRelative(ty, segment) => { - let segment = self.process_segment(span, segment, &mut generics.child, false); + let segment = self.process_segment(span, segment, &mut generics.child); hir::QPath::TypeRelative(ty, self.arena.alloc(segment)) } @@ -584,13 +580,12 @@ impl<'hir, R: ResolverAstLoweringExt<'hir>> LoweringContext<'_, 'hir, R> { span: Span, segment: &hir::PathSegment<'hir>, result: &mut GenericsGenerationResult<'hir>, - add_lifetimes: bool, ) -> hir::PathSegment<'hir> { let details = result.generics.args_propagation_details(); let segment = if details.should_propagate { let generics = result.generics.into_hir_generics(self, span); - let args = generics.into_generic_args(self, add_lifetimes, span); + let args = generics.into_generic_args(self, span); // Needed for better error messages (`trait-impl-wrong-args-count.rs` test). let args = if args.is_empty() { None } else { Some(args) }; diff --git a/compiler/rustc_ast_lowering/src/delegation/generics.rs b/compiler/rustc_ast_lowering/src/delegation/generics.rs index 201f6bfb4bd63..503877cff9785 100644 --- a/compiler/rustc_ast_lowering/src/delegation/generics.rs +++ b/compiler/rustc_ast_lowering/src/delegation/generics.rs @@ -6,7 +6,7 @@ use rustc_hir::def_id::DefId; use rustc_middle::ty::GenericParamDefKind; use rustc_middle::{bug, ty}; use rustc_span::symbol::kw; -use rustc_span::{Ident, Span}; +use rustc_span::{Ident, Span, sym}; use crate::{LoweringContext, ResolverAstLoweringExt}; @@ -25,22 +25,37 @@ pub(super) enum DelegationGenericsKind { TraitImpl(bool /* Has user-specified args */), } +#[derive(Debug, Clone, Copy)] +pub(super) enum GenericsPosition { + Parent, + Child, +} + pub(super) struct DelegationGenerics { generics: T, kind: DelegationGenericsKind, + pos: GenericsPosition, } impl<'hir> DelegationGenerics<&'hir [ty::GenericParamDef]> { - fn default(generics: &'hir [ty::GenericParamDef]) -> Self { - DelegationGenerics { generics, kind: DelegationGenericsKind::Default } + fn default(generics: &'hir [ty::GenericParamDef], pos: GenericsPosition) -> Self { + DelegationGenerics { generics, pos, kind: DelegationGenericsKind::Default } } - fn user_specified(generics: &'hir [ty::GenericParamDef]) -> Self { - DelegationGenerics { generics, kind: DelegationGenericsKind::UserSpecified } + fn user_specified(generics: &'hir [ty::GenericParamDef], pos: GenericsPosition) -> Self { + DelegationGenerics { generics, pos, kind: DelegationGenericsKind::UserSpecified } } - fn trait_impl(generics: &'hir [ty::GenericParamDef], user_specified: bool) -> Self { - DelegationGenerics { generics, kind: DelegationGenericsKind::TraitImpl(user_specified) } + fn trait_impl( + generics: &'hir [ty::GenericParamDef], + user_specified: bool, + pos: GenericsPosition, + ) -> Self { + DelegationGenerics { + generics, + pos, + kind: DelegationGenericsKind::TraitImpl(user_specified), + } } } @@ -103,8 +118,14 @@ impl<'hir> HirOrTyGenerics<'hir> { span: Span, ) -> &mut HirOrTyGenerics<'hir> { if let HirOrTyGenerics::Ty(ty) = self { - let params = ctx.uplift_delegation_generic_params(span, ty.generics); - *self = HirOrTyGenerics::Hir(DelegationGenerics { generics: params, kind: ty.kind }); + let rename_self = matches!(ty.pos, GenericsPosition::Child); + let params = ctx.uplift_delegation_generic_params(span, ty.generics, rename_self); + + *self = HirOrTyGenerics::Hir(DelegationGenerics { + generics: params, + kind: ty.kind, + pos: ty.pos, + }); } self @@ -120,7 +141,6 @@ impl<'hir> HirOrTyGenerics<'hir> { pub(super) fn into_generic_args( &self, ctx: &mut LoweringContext<'_, 'hir, impl ResolverAstLoweringExt<'hir>>, - add_lifetimes: bool, span: Span, ) -> &'hir hir::GenericArgs<'hir> { match self { @@ -128,6 +148,7 @@ impl<'hir> HirOrTyGenerics<'hir> { bug!("Attempting to get generic args before uplifting to HIR") } HirOrTyGenerics::Hir(hir) => { + let add_lifetimes = matches!(hir.pos, GenericsPosition::Parent); ctx.create_generics_args_from_params(hir.generics.params, add_lifetimes, span) } } @@ -227,10 +248,15 @@ impl<'hir, R: ResolverAstLoweringExt<'hir>> LoweringContext<'_, 'hir, R> { if matches!(delegation_parent_kind, DefKind::Impl { of_trait: true }) { // Considering parent generics, during signature inheritance // we will take those args that are in trait impl header trait ref. - let parent = DelegationGenerics::trait_impl(&[], true); + let parent = DelegationGenerics::trait_impl(&[], true, GenericsPosition::Parent); let parent = GenericsGenerationResult::new(parent); - let child = DelegationGenerics::trait_impl(sig_params, child_user_specified); + let child = DelegationGenerics::trait_impl( + sig_params, + child_user_specified, + GenericsPosition::Child, + ); + let child = GenericsGenerationResult::new(child); return GenericsGenerationResults { @@ -263,25 +289,32 @@ impl<'hir, R: ResolverAstLoweringExt<'hir>> LoweringContext<'_, 'hir, R> { DelegationGenerics { kind: DelegationGenericsKind::SelfAndUserSpecified, generics: &sig_parent_params[..1], + pos: GenericsPosition::Parent, } } else { - DelegationGenerics::user_specified(&[]) + DelegationGenerics::user_specified(&[], GenericsPosition::Parent) } } else { let skip_self = usize::from(!generate_self); - DelegationGenerics::default(&sig_parent_params[skip_self..]) + DelegationGenerics::default( + &sig_parent_params[skip_self..], + GenericsPosition::Parent, + ) } } else { - DelegationGenerics::default(&[]) + DelegationGenerics::default(&[], GenericsPosition::Parent) }; let child_generics = if child_user_specified { let synth_params_index = sig_params.iter().position(|p| p.kind.is_synthetic()).unwrap_or(sig_params.len()); - DelegationGenerics::user_specified(&sig_params[synth_params_index..]) + DelegationGenerics::user_specified( + &sig_params[synth_params_index..], + GenericsPosition::Child, + ) } else { - DelegationGenerics::default(sig_params) + DelegationGenerics::default(sig_params, GenericsPosition::Child) }; GenericsGenerationResults { @@ -296,6 +329,7 @@ impl<'hir, R: ResolverAstLoweringExt<'hir>> LoweringContext<'_, 'hir, R> { &mut self, span: Span, params: &'hir [ty::GenericParamDef], + rename_self: bool, ) -> &'hir hir::Generics<'hir> { let params = self.arena.alloc_from_iter(params.iter().map(|p| { let def_kind = match p.kind { @@ -304,7 +338,20 @@ impl<'hir, R: ResolverAstLoweringExt<'hir>> LoweringContext<'_, 'hir, R> { GenericParamDefKind::Const { .. } => DefKind::ConstParam, }; - let param_ident = Ident::new(p.name, span); + // Rename Self generic param to This so it is properly propagated. + // If the user will create a function `fn foo() {}` with generic + // param "Self" then it will not be generated in HIR, the same thing + // applies to traits, `trait Trait {}` will be represented as + // `trait Trait {}` in HIR and "unexpected keyword `Self` in generic parameters" + // error will be emitted. + // Note that we do not rename `Self` to `This` after non-recursive reuse + // from Trait, in this case the `Self` should not be propagated + // (we rely that implicit `Self` generic param of a trait is named "Self") + // and it is OK to have Self generic param generated during lowering. + let param_name = + if rename_self && p.name == kw::SelfUpper { sym::This } else { p.name }; + + let param_ident = Ident::new(param_name, span); let def_name = Some(param_ident.name); let node_id = self.next_node_id(); diff --git a/tests/pretty/delegation-self-rename.pp b/tests/pretty/delegation-self-rename.pp new file mode 100644 index 0000000000000..59a07315185c7 --- /dev/null +++ b/tests/pretty/delegation-self-rename.pp @@ -0,0 +1,55 @@ +#![attr = Feature([fn_delegation#0])] +extern crate std; +#[attr = PreludeImport] +use ::std::prelude::rust_2015::*; +//@ pretty-compare-only +//@ pretty-mode:hir +//@ pp-exact:delegation-self-rename.pp + + +trait Trait<'a, A, const B: bool> { + fn foo<'b, const B2: bool, T, U, + impl FnOnce() -> usize>(&self, f: impl FnOnce() -> usize) -> usize + where impl FnOnce() -> usize: FnOnce() -> usize { f() + 1 } +} + +struct X; +impl <'a, A, const B: bool> Trait<'a, A, B> for X { } + +#[attr = Inline(Hint)] +fn foo<'a, Self, A, const B: _, const B2: _, T, U, + impl FnOnce() -> usize>(self: _, arg1: _) -> _ where + 'a:'a { self.foo::(arg1) } +#[attr = Inline(Hint)] +fn bar usize>(self: _, arg1: _) + -> _ { Trait::<'static, (), true>::foo::(self, arg1) } + +#[attr = Inline(Hint)] +fn foo2<'a, This, A, const B: _, const B2: _, T, U, + impl FnOnce() -> usize>(arg0: _, arg1: _) -> _ where + 'a:'a { foo::(arg0, arg1) } +#[attr = Inline(Hint)] +fn bar2 usize>(arg0: _, arg1: _) + -> _ { bar::(arg0, arg1) } + +trait Trait2 { + #[attr = Inline(Hint)] + fn foo3<'a, This, A, const B: _, const B2: _, T, U, + impl FnOnce() -> usize>(arg0: _, arg1: _) -> _ where + 'a:'a { foo2::(arg0, arg1) } + #[attr = Inline(Hint)] + fn bar3 usize>(arg0: _, arg1: _) + -> _ { bar2::(arg0, arg1) } +} + +impl Trait2 for () { } + +#[attr = Inline(Hint)] +fn foo4<'a, This, A, const B: _, const B2: _, T, U, + impl FnOnce() -> usize>(arg0: _, arg1: _) -> _ where + 'a:'a { <() as Trait2>::foo3::(arg0, arg1) } +#[attr = Inline(Hint)] +fn bar4 usize>(arg0: _, arg1: _) + -> _ { <() as Trait2>::bar3::(arg0, arg1) } + +fn main() { } diff --git a/tests/pretty/delegation-self-rename.rs b/tests/pretty/delegation-self-rename.rs new file mode 100644 index 0000000000000..9054bb2b89571 --- /dev/null +++ b/tests/pretty/delegation-self-rename.rs @@ -0,0 +1,32 @@ +//@ pretty-compare-only +//@ pretty-mode:hir +//@ pp-exact:delegation-self-rename.pp + +#![feature(fn_delegation)] + +trait Trait<'a, A, const B: bool> { + fn foo<'b, const B2: bool, T, U>(&self, f: impl FnOnce() -> usize) -> usize { + f() + 1 + } +} + +struct X; +impl<'a, A, const B: bool> Trait<'a, A, B> for X {} + +reuse Trait::foo; +reuse Trait::<'static, (), true>::foo:: as bar; + +reuse foo as foo2; +reuse bar as bar2; + +trait Trait2 { + reuse foo2 as foo3; + reuse bar2 as bar3; +} + +impl Trait2 for () {} + +reuse <() as Trait2>::foo3 as foo4; +reuse <() as Trait2>::bar3 as bar4; + +fn main() {} diff --git a/tests/ui/delegation/generics/self-rename.rs b/tests/ui/delegation/generics/self-rename.rs new file mode 100644 index 0000000000000..a4c92cecb5c6b --- /dev/null +++ b/tests/ui/delegation/generics/self-rename.rs @@ -0,0 +1,45 @@ +//@ run-pass + +#![feature(fn_delegation)] + +trait Trait<'a, A, const B: bool> { + fn foo<'b, const B2: bool, T, U>(&self, f: impl FnOnce() -> usize) -> usize { + f() + 1 + } +} + +struct X; +impl<'a, A, const B: bool> Trait<'a, A, B> for X {} + +reuse Trait::foo; +reuse Trait::<'static, (), true>::foo:: as bar; + +reuse foo as foo2; +reuse bar as bar2; + +trait Trait2 { + reuse foo2 as foo3; + reuse bar2 as bar3; +} + +impl Trait2 for () {} + +reuse <() as Trait2>::foo3 as foo4; +reuse <() as Trait2>::bar3 as bar4; + +fn main() { + assert_eq!(foo::<'static, X, (), true, false, (), ()>(&X, || 123), 124); + assert_eq!(foo2::<'static, X, (), true, false, (), ()>(&X, || 123), 124); + assert_eq!(<()>::foo3::<'static, X, (), true, false, (), ()>(&X, || 123), 124); + assert_eq!(foo4::<'static, X, (), true, false, (), ()>(&X, || 123), 124); + + assert_eq!(bar::(&X, || 123), 124); + assert_eq!(bar2::(&X, || 123), 124); + assert_eq!(<()>::bar3::(&X, || 123), 124); + assert_eq!(bar4::(&X, || 123), 124); + + assert_eq!(bar(&X, || 123), 124); + assert_eq!(bar2(&X, || 123), 124); + assert_eq!(<()>::bar3(&X, || 123), 124); + assert_eq!(bar4::(&X, || 123), 124); +} diff --git a/tests/ui/delegation/generics/synth-params-ice-154780.rs b/tests/ui/delegation/generics/synth-params-ice-154780.rs index 3ea52818a8f08..ef8684698612f 100644 --- a/tests/ui/delegation/generics/synth-params-ice-154780.rs +++ b/tests/ui/delegation/generics/synth-params-ice-154780.rs @@ -62,40 +62,49 @@ mod test_3 { } } -// FIXME(fn_delegation): rename Self generic param in recursive delegations -// mod test_4 { -// trait Trait<'a, A, const B: bool> { -// fn foo<'b, const B2: bool, T, U>(&self, f: impl FnOnce() -> usize) -> usize { -// f() -// } -// } - -// struct X; -// impl<'a, A, const B: bool> Trait<'a, A, B> for X {} - -// reuse Trait::foo; -// reuse Trait::<'static, (), true>::foo:: as bar; - -// trait Trait2 { -// reuse foo; -// reuse bar; -// } - -// reuse Trait2::foo as foo2; -// reuse Trait2::foo::<'static, X, (), true, false, (), ()> as foo3; -// reuse Trait2::bar as bar2; -// reuse Trait2::bar:: as bar3; - -// pub fn check() { -// assert_eq!(foo::<'static, X, (), true, false, (), ()>(&X, || 123), 123); -// assert_eq!(bar::(&X, || 123), 123); -// assert_eq!(bar(&X, || 123), 123); -// } -// } +// Test recursive delegation through trait +mod test_4 { + trait Trait<'a, A, const B: bool> { + fn foo<'b, const B2: bool, T, U>(&self, f: impl FnOnce() -> usize) -> usize { + f() + } + } + + struct X; + impl<'a, A, const B: bool> Trait<'a, A, B> for X {} + + reuse Trait::foo; + reuse Trait::<'static, (), true>::foo:: as bar; + + trait Trait2 { + reuse foo; + reuse bar; + } + + impl Trait2 for () {} + + reuse <() as Trait2>::foo as foo2; + reuse <() as Trait2>::foo::<'static, X, (), true, false, (), ()> as foo3; + reuse <() as Trait2>::bar as bar2; + reuse <() as Trait2>::bar:: as bar3; + + pub fn check() { + assert_eq!(foo::<'static, X, (), true, false, (), ()>(&X, || 123), 123); + assert_eq!(bar::(&X, || 123), 123); + assert_eq!(bar(&X, || 123), 123); + + assert_eq!(foo2::<'static, X, (), true, false, (), ()>(&X, || 123), 123); + assert_eq!(bar2::(&X, || 123), 123); + assert_eq!(bar2(&X, || 123), 123); + + assert_eq!(foo3(&X, || 123), 123); + assert_eq!(bar3(&X, || 123), 123); + } +} fn main() { test_1::check(); test_2::check(); test_3::check(); - // test_4::check(); + test_4::check(); } From 27e12b89b7984e009364febdb11d583ef64a27bf Mon Sep 17 00:00:00 2001 From: cezarbbb Date: Fri, 24 Apr 2026 15:52:21 +0800 Subject: [PATCH 160/183] Fix tier level for 5 thumb bare-metal ARM targets --- compiler/rustc_target/src/spec/targets/thumbv7a_none_eabi.rs | 2 +- compiler/rustc_target/src/spec/targets/thumbv7a_none_eabihf.rs | 2 +- compiler/rustc_target/src/spec/targets/thumbv7r_none_eabi.rs | 2 +- compiler/rustc_target/src/spec/targets/thumbv7r_none_eabihf.rs | 2 +- compiler/rustc_target/src/spec/targets/thumbv8r_none_eabihf.rs | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/compiler/rustc_target/src/spec/targets/thumbv7a_none_eabi.rs b/compiler/rustc_target/src/spec/targets/thumbv7a_none_eabi.rs index 011307a50c346..4e20f04173f0e 100644 --- a/compiler/rustc_target/src/spec/targets/thumbv7a_none_eabi.rs +++ b/compiler/rustc_target/src/spec/targets/thumbv7a_none_eabi.rs @@ -7,7 +7,7 @@ pub(crate) fn target() -> Target { llvm_target: "thumbv7a-none-eabi".into(), metadata: TargetMetadata { description: Some("Thumb-mode Bare Armv7-A".into()), - tier: Some(2), + tier: Some(3), host_tools: Some(false), std: Some(false), }, diff --git a/compiler/rustc_target/src/spec/targets/thumbv7a_none_eabihf.rs b/compiler/rustc_target/src/spec/targets/thumbv7a_none_eabihf.rs index 4baa73c3cdb8b..bf4241a47277a 100644 --- a/compiler/rustc_target/src/spec/targets/thumbv7a_none_eabihf.rs +++ b/compiler/rustc_target/src/spec/targets/thumbv7a_none_eabihf.rs @@ -7,7 +7,7 @@ pub(crate) fn target() -> Target { llvm_target: "thumbv7a-none-eabihf".into(), metadata: TargetMetadata { description: Some("Thumb-mode Bare Armv7-A, hardfloat".into()), - tier: Some(2), + tier: Some(3), host_tools: Some(false), std: Some(false), }, diff --git a/compiler/rustc_target/src/spec/targets/thumbv7r_none_eabi.rs b/compiler/rustc_target/src/spec/targets/thumbv7r_none_eabi.rs index da66a53432003..296a1d00bad3b 100644 --- a/compiler/rustc_target/src/spec/targets/thumbv7r_none_eabi.rs +++ b/compiler/rustc_target/src/spec/targets/thumbv7r_none_eabi.rs @@ -7,7 +7,7 @@ pub(crate) fn target() -> Target { llvm_target: "thumbv7r-none-eabi".into(), metadata: TargetMetadata { description: Some("Thumb-mode Bare Armv7-R".into()), - tier: Some(2), + tier: Some(3), host_tools: Some(false), std: Some(false), }, diff --git a/compiler/rustc_target/src/spec/targets/thumbv7r_none_eabihf.rs b/compiler/rustc_target/src/spec/targets/thumbv7r_none_eabihf.rs index d591db8faf6a8..8d5ac8a2d0a36 100644 --- a/compiler/rustc_target/src/spec/targets/thumbv7r_none_eabihf.rs +++ b/compiler/rustc_target/src/spec/targets/thumbv7r_none_eabihf.rs @@ -7,7 +7,7 @@ pub(crate) fn target() -> Target { llvm_target: "thumbv7r-none-eabihf".into(), metadata: TargetMetadata { description: Some("Thumb-mode Bare Armv7-R, hardfloat".into()), - tier: Some(2), + tier: Some(3), host_tools: Some(false), std: Some(false), }, diff --git a/compiler/rustc_target/src/spec/targets/thumbv8r_none_eabihf.rs b/compiler/rustc_target/src/spec/targets/thumbv8r_none_eabihf.rs index 459dff9c1aa9b..808287ffa3d64 100644 --- a/compiler/rustc_target/src/spec/targets/thumbv8r_none_eabihf.rs +++ b/compiler/rustc_target/src/spec/targets/thumbv8r_none_eabihf.rs @@ -7,7 +7,7 @@ pub(crate) fn target() -> Target { llvm_target: "thumbv8r-none-eabihf".into(), metadata: TargetMetadata { description: Some("Thumb-mode Bare Armv8-R, hardfloat".into()), - tier: Some(2), + tier: Some(3), host_tools: Some(false), std: Some(false), }, From 150905c3de2608e3ad793dda07f81ec25670e872 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Fri, 24 Apr 2026 02:10:49 +0000 Subject: [PATCH 161/183] test: Add a regression test for Apple platforms aborting on `free` Add a regression test for RUST-150898 to make users aware that if this test fails, they may encounter unusual behavior elsewhere. Original repro authored by dianqk. --- .../regression-abort-on-free-issue-150898.rs | 59 +++++++++++++++++++ 1 file changed, 59 insertions(+) create mode 100644 tests/ui/allocator/regression-abort-on-free-issue-150898.rs diff --git a/tests/ui/allocator/regression-abort-on-free-issue-150898.rs b/tests/ui/allocator/regression-abort-on-free-issue-150898.rs new file mode 100644 index 0000000000000..41a7695bee77c --- /dev/null +++ b/tests/ui/allocator/regression-abort-on-free-issue-150898.rs @@ -0,0 +1,59 @@ +// Regression test for https://github.com/rust-lang/rust/issues/150898 +// +// This test fails on Apple platforms with versions containing an allocator +// bug. If this fails with SIGABRT, you may need to upgrade your system to +// avoid other unexpected behavior. +// +// Note that the failure is non-deterministic so this test may pass even in +// conditions where the bug is present. That being said, on the author's +// machine this has a 100% rate of hitting the crash on at least a couple +// threads. +// +// The bug was resolved by macOS 26.4. + +//@ run-pass +//@ only-aarch64-apple-darwin +//@ compile-flags: -C opt-level=1 -C codegen-units=1 + +use std::thread; + +fn main() { + // Running with multiple threads substantially increases the change of + // hitting the bug. + thread::scope(|s| { + for _ in 0..10 { + s.spawn(run); + } + }); +} + +fn run() { + // This doesn't always fail, so rerun a few times + for _ in 0..100 { + unsafe { + core::arch::asm!( + " + // Alloc 18 bytes + mov x0, #18 + bl _malloc + // Save the pointer to x21 + mov x21, x0 + // Alloc 18 bytes again + mov x0, #18 + bl _malloc + // Store the contents of `x13` to the second allocation. `x13` is the + // magic register to cause the crash, other registers work well. + str x13, [x0] + // Free the pointers + bl _free + mov x0, x21 + bl _free + ", + out("x0") _, + out("x13") _, + out("x21") _, + clobber_abi("C"), + ) + } + } +} From e90878b9f25133c727b434b9002b26c0ec63e5b6 Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Tue, 21 Apr 2026 12:44:13 +0200 Subject: [PATCH 162/183] All nested statics in a single interning run have the same parent So we do not need to disambiguate considering parents --- .../rustc_const_eval/src/interpret/intern.rs | 28 +++++++++---------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/compiler/rustc_const_eval/src/interpret/intern.rs b/compiler/rustc_const_eval/src/interpret/intern.rs index 57139d077d493..2f27b7e5082f2 100644 --- a/compiler/rustc_const_eval/src/interpret/intern.rs +++ b/compiler/rustc_const_eval/src/interpret/intern.rs @@ -16,10 +16,7 @@ use hir::def::DefKind; use rustc_ast::Mutability; use rustc_data_structures::fx::{FxHashSet, FxIndexMap}; -use rustc_hir::def_id::LocalDefIdMap; -use rustc_hir::definitions::{ - DefPathData, PerParentDisambiguatorState, PerParentDisambiguatorsMap, -}; +use rustc_hir::definitions::{DefPathData, PerParentDisambiguatorState}; use rustc_hir::{self as hir}; use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrs; use rustc_middle::mir::interpret::{ @@ -108,7 +105,7 @@ fn intern_shallow<'tcx, M: CompileTimeMachine<'tcx>>( ecx: &mut InterpCx<'tcx, M>, alloc_id: AllocId, mutability: Mutability, - disambiguators: Option<&mut LocalDefIdMap>, + disambiguator: Option<&mut PerParentDisambiguatorState>, ) -> Result + 'tcx, InternError> { trace!("intern_shallow {:?}", alloc_id); // remove allocation @@ -132,7 +129,7 @@ fn intern_shallow<'tcx, M: CompileTimeMachine<'tcx>>( static_id, alloc_id, alloc, - disambiguators.expect("disambiguators needed"), + disambiguator.expect("disambiguator needed"), ); } else { ecx.tcx.set_alloc_id_memory(alloc_id, alloc); @@ -147,19 +144,18 @@ fn intern_as_new_static<'tcx>( static_id: LocalDefId, alloc_id: AllocId, alloc: ConstAllocation<'tcx>, - disambiguators: &mut LocalDefIdMap, + disambiguator: &mut PerParentDisambiguatorState, ) { - // `intern_const_alloc_recursive` is called once per static and it contains the `DisambiguatorState`. + // `intern_const_alloc_recursive` is called once per static and it contains the `PerParentDisambiguatorState`. // The `::{{nested}}` path is thus unique to `intern_const_alloc_recursive` and the - // `DisambiguatorState` ensures the generated path is unique for this call as we generate + // `PerParentDisambiguatorState` ensures the generated path is unique for this call as we generate // `::{{nested#n}}` where `n` is the `n`th `intern_as_new_static` call. let feed = tcx.create_def( static_id, None, DefKind::Static { safety: hir::Safety::Safe, mutability: alloc.0.mutability, nested: true }, Some(DefPathData::NestedStatic), - //FIXME(oli-obk): cleanup (https://github.com/rust-lang/rust/pull/155547#discussion_r3110792640) - disambiguators.get_or_create(static_id), + disambiguator, ); tcx.set_nested_alloc_id_static(alloc_id, feed.def_id()); @@ -209,7 +205,9 @@ pub fn intern_const_alloc_recursive<'tcx, M: CompileTimeMachine<'tcx>>( intern_kind: InternKind, ret: &MPlaceTy<'tcx>, ) -> Result<(), InternError> { - let mut disambiguators = Default::default(); + let mut disambiguator = + ecx.machine.static_def_id().map(|id| PerParentDisambiguatorState::new(id)); + let mut disambiguator = disambiguator.as_mut(); // We are interning recursively, and for mutability we are distinguishing the "root" allocation // that we are starting in, and all other allocations that we are encountering recursively. @@ -248,13 +246,15 @@ pub fn intern_const_alloc_recursive<'tcx, M: CompileTimeMachine<'tcx>>( // This gives us the initial set of nested allocations, which will then all be processed // recursively in the loop below. let mut todo: Vec<_> = if is_static { + assert!(disambiguator.is_some()); // Do not steal the root allocation, we need it later to create the return value of `eval_static_initializer`. // But still change its mutability to match the requested one. let (kind, alloc) = ecx.memory.alloc_map.get_mut(&base_alloc_id).unwrap(); prepare_alloc(*ecx.tcx, *kind, alloc, base_mutability)?; alloc.provenance().ptrs().iter().map(|&(_, prov)| prov).collect() } else { - intern_shallow(ecx, base_alloc_id, base_mutability, Some(&mut disambiguators))?.collect() + assert!(disambiguator.is_none()); + intern_shallow(ecx, base_alloc_id, base_mutability, None)?.collect() }; // We need to distinguish "has just been interned" from "was already in `tcx`", // so we track this in a separate set. @@ -336,7 +336,7 @@ pub fn intern_const_alloc_recursive<'tcx, M: CompileTimeMachine<'tcx>>( // okay with losing some potential for immutability here. This can anyway only affect // `static mut`. just_interned.insert(alloc_id); - let next = intern_shallow(ecx, alloc_id, inner_mutability, Some(&mut disambiguators))?; + let next = intern_shallow(ecx, alloc_id, inner_mutability, disambiguator.as_deref_mut())?; todo.extend(next); } if found_bad_mutable_ptr { From bfb085da9fa218a45a7bae9f68d731aa48b2ae77 Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Fri, 24 Apr 2026 12:50:21 +0200 Subject: [PATCH 163/183] All generated associated types for opaque types in traits/impls have the same parent --- compiler/rustc_ty_utils/src/assoc.rs | 24 +++++++++++------------- 1 file changed, 11 insertions(+), 13 deletions(-) diff --git a/compiler/rustc_ty_utils/src/assoc.rs b/compiler/rustc_ty_utils/src/assoc.rs index 1d24a207103c8..443f33aaa0b01 100644 --- a/compiler/rustc_ty_utils/src/assoc.rs +++ b/compiler/rustc_ty_utils/src/assoc.rs @@ -1,8 +1,6 @@ use rustc_hir::def::DefKind; -use rustc_hir::def_id::{DefId, DefIdMap, LocalDefId, LocalDefIdMap}; -use rustc_hir::definitions::{ - DefPathData, PerParentDisambiguatorState, PerParentDisambiguatorsMap, -}; +use rustc_hir::def_id::{DefId, DefIdMap, LocalDefId}; +use rustc_hir::definitions::{DefPathData, PerParentDisambiguatorState}; use rustc_hir::intravisit::{self, Visitor}; use rustc_hir::{self as hir, ConstItemRhs, ImplItemImplKind, ItemKind}; use rustc_middle::query::Providers; @@ -131,7 +129,7 @@ struct RPITVisitor<'a, 'tcx> { tcx: TyCtxt<'tcx>, synthetics: Vec, data: DefPathData, - disambiguators: &'a mut LocalDefIdMap, + disambiguator: &'a mut PerParentDisambiguatorState, } impl<'tcx> Visitor<'tcx> for RPITVisitor<'_, 'tcx> { @@ -140,7 +138,7 @@ impl<'tcx> Visitor<'tcx> for RPITVisitor<'_, 'tcx> { self.tcx, opaque.def_id, self.data, - &mut self.disambiguators, + &mut self.disambiguator, )); intravisit::walk_opaque_ty(self, opaque) } @@ -151,7 +149,7 @@ fn associated_types_for_impl_traits_in_trait_or_impl<'tcx>( def_id: LocalDefId, ) -> DefIdMap> { let item = tcx.hir_expect_item(def_id); - let disambiguators = &mut Default::default(); + let disambiguator = &mut PerParentDisambiguatorState::new(def_id); match item.kind { ItemKind::Trait(.., trait_item_refs) => trait_item_refs .iter() @@ -165,7 +163,7 @@ fn associated_types_for_impl_traits_in_trait_or_impl<'tcx>( }; let def_name = tcx.item_name(fn_def_id.to_def_id()); let data = DefPathData::AnonAssocTy(def_name); - let mut visitor = RPITVisitor { tcx, synthetics: vec![], data, disambiguators }; + let mut visitor = RPITVisitor { tcx, synthetics: vec![], data, disambiguator }; visitor.visit_fn_ret_ty(output); let defs = visitor .synthetics @@ -199,7 +197,7 @@ fn associated_types_for_impl_traits_in_trait_or_impl<'tcx>( return Some((did, vec![])); }; let iter = in_trait_def[&trait_item_def_id].iter().map(|&id| { - associated_type_for_impl_trait_in_impl(tcx, id, item, disambiguators) + associated_type_for_impl_trait_in_impl(tcx, id, item, disambiguator) .to_def_id() }); Some((did, iter.collect())) @@ -223,7 +221,7 @@ fn associated_type_for_impl_trait_in_trait( tcx: TyCtxt<'_>, opaque_ty_def_id: LocalDefId, data: DefPathData, - disambiguators: &mut LocalDefIdMap, + disambiguator: &mut PerParentDisambiguatorState, ) -> LocalDefId { let (hir::OpaqueTyOrigin::FnReturn { parent: fn_def_id, .. } | hir::OpaqueTyOrigin::AsyncFn { parent: fn_def_id, .. }) = @@ -242,7 +240,7 @@ fn associated_type_for_impl_trait_in_trait( None, DefKind::AssocTy, Some(data), - disambiguators.get_or_create(trait_def_id), + disambiguator, ); let local_def_id = trait_assoc_ty.def_id(); @@ -285,7 +283,7 @@ fn associated_type_for_impl_trait_in_impl( tcx: TyCtxt<'_>, trait_assoc_def_id: DefId, impl_fn: &hir::ImplItem<'_>, - disambiguators: &mut LocalDefIdMap, + disambiguator: &mut PerParentDisambiguatorState, ) -> LocalDefId { let impl_local_def_id = tcx.local_parent(impl_fn.owner_id.def_id); @@ -308,7 +306,7 @@ fn associated_type_for_impl_trait_in_impl( None, DefKind::AssocTy, Some(data), - disambiguators.get_or_create(impl_local_def_id), + disambiguator, ); let local_def_id = impl_assoc_ty.def_id(); From bbdc7c4cc5f80369ad94d4ac1fc5cf7da1f93ba0 Mon Sep 17 00:00:00 2001 From: Jynn Nelson Date: Fri, 24 Apr 2026 13:59:31 +0200 Subject: [PATCH 164/183] bootstrap: Don't clone submodules unconditionally in dry-run This made it very annoying to debug bootstrap itself, because every `--dry-run` invocation would start out by cloning LLVM, which is almost never necessary. Instead change a few Steps to properly support dry_run when no submodule is checked out. --- src/bootstrap/src/core/config/config.rs | 21 +++++---------------- src/bootstrap/src/lib.rs | 4 ++++ 2 files changed, 9 insertions(+), 16 deletions(-) diff --git a/src/bootstrap/src/core/config/config.rs b/src/bootstrap/src/core/config/config.rs index babcafb024e07..b933e668c26ae 100644 --- a/src/bootstrap/src/core/config/config.rs +++ b/src/bootstrap/src/core/config/config.rs @@ -2448,17 +2448,7 @@ pub(crate) fn update_submodule<'a>( return; } - // Submodule updating actually happens during in the dry run mode. We need to make sure that - // all the git commands below are actually executed, because some follow-up code - // in bootstrap might depend on the submodules being checked out. Furthermore, not all - // the command executions below work with an empty output (produced during dry run). - // Therefore, all commands below are marked with `run_in_dry_run()`, so that they also run in - // dry run mode. - let submodule_git = || { - let mut cmd = helpers::git(Some(&absolute_path)); - cmd.run_in_dry_run(); - cmd - }; + let submodule_git = || helpers::git(Some(&absolute_path)); // Determine commit checked out in submodule. let checked_out_hash = @@ -2466,7 +2456,7 @@ pub(crate) fn update_submodule<'a>( let checked_out_hash = checked_out_hash.trim_end(); // Determine commit that the submodule *should* have. let recorded = helpers::git(Some(dwn_ctx.src)) - .run_in_dry_run() + .run_in_dry_run() // otherwise parsing `actual_hash` fails .args(["ls-tree", "HEAD"]) .arg(relative_path) .run_capture_stdout(dwn_ctx.exec_ctx) @@ -2482,11 +2472,12 @@ pub(crate) fn update_submodule<'a>( return; } - println!("Updating submodule {relative_path}"); + if !dwn_ctx.exec_ctx.dry_run() { + println!("Updating submodule {relative_path}"); + }; helpers::git(Some(dwn_ctx.src)) .allow_failure() - .run_in_dry_run() .args(["submodule", "-q", "sync"]) .arg(relative_path) .run(dwn_ctx.exec_ctx); @@ -2497,12 +2488,10 @@ pub(crate) fn update_submodule<'a>( // even though that has no relation to the upstream for the submodule. let current_branch = helpers::git(Some(dwn_ctx.src)) .allow_failure() - .run_in_dry_run() .args(["symbolic-ref", "--short", "HEAD"]) .run_capture(dwn_ctx.exec_ctx); let mut git = helpers::git(Some(dwn_ctx.src)).allow_failure(); - git.run_in_dry_run(); if current_branch.is_success() { // If there is a tag named after the current branch, git will try to disambiguate by prepending `heads/` to the branch name. // This syntax isn't accepted by `branch.{branch}`. Strip it. diff --git a/src/bootstrap/src/lib.rs b/src/bootstrap/src/lib.rs index 6af11d9ae0a81..fd3d129c231d7 100644 --- a/src/bootstrap/src/lib.rs +++ b/src/bootstrap/src/lib.rs @@ -676,6 +676,10 @@ impl Build { return; } + if self.config.dry_run() { + return; + } + // When testing bootstrap itself, it is much faster to ignore // submodules. Almost all Steps work fine without their submodules. if cfg!(test) && !self.config.submodules() { From 52b93e04f8ef0323297b38ebbe4ce927e9e43185 Mon Sep 17 00:00:00 2001 From: Muhtasim-Rasheed Date: Fri, 24 Apr 2026 18:17:26 +0600 Subject: [PATCH 165/183] Fix typo by removing extra 'to' --- library/core/src/convert/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/core/src/convert/mod.rs b/library/core/src/convert/mod.rs index 4a4c7ee388f9e..85d42b57dc06e 100644 --- a/library/core/src/convert/mod.rs +++ b/library/core/src/convert/mod.rs @@ -11,7 +11,7 @@ //! - The [`TryFrom`] and [`TryInto`] traits behave like [`From`] and [`Into`], //! but should be implemented when the conversion can fail. //! -//! The traits in this module are often used as trait bounds for generic functions such that to +//! The traits in this module are often used as trait bounds for generic functions such that //! arguments of multiple types are supported. See the documentation of each trait for examples. //! //! As a library author, you should always prefer implementing [`From`][`From`] or From ece632c9f7afdf4b5c07ee2e48c347ed0a71d401 Mon Sep 17 00:00:00 2001 From: Makai Date: Fri, 24 Apr 2026 21:25:20 +0800 Subject: [PATCH 166/183] Remove `AllVariants` workaround for rust-analyzer --- compiler/rustc_session/src/config/print_request.rs | 5 ----- 1 file changed, 5 deletions(-) diff --git a/compiler/rustc_session/src/config/print_request.rs b/compiler/rustc_session/src/config/print_request.rs index dc53fcc6955f7..b87236cef7646 100644 --- a/compiler/rustc_session/src/config/print_request.rs +++ b/compiler/rustc_session/src/config/print_request.rs @@ -50,11 +50,6 @@ pub enum PrintKind { } impl PrintKind { - /// FIXME: rust-analyzer doesn't support `#![feature(macro_derive)]` yet - /// (), which breaks autocomplete. - /// Work around that by aliasing the trait constant to a regular constant. - const ALL_VARIANTS: &[Self] = ::ALL_VARIANTS; - fn name(self) -> &'static str { use PrintKind::*; match self { From 84ebb2269e4b530789b6f7bae00b1ec9a80bc630 Mon Sep 17 00:00:00 2001 From: Walnut <39544927+Walnut356@users.noreply.github.com> Date: Fri, 24 Apr 2026 08:54:21 -0500 Subject: [PATCH 167/183] account for `GetSyntheticValue` failures --- src/etc/lldb_providers.py | 53 ++++++++++++++++++++++----------------- 1 file changed, 30 insertions(+), 23 deletions(-) diff --git a/src/etc/lldb_providers.py b/src/etc/lldb_providers.py index ef3f94ee83530..df2bdf8e58a3d 100644 --- a/src/etc/lldb_providers.py +++ b/src/etc/lldb_providers.py @@ -108,8 +108,6 @@ def num_children(self) -> int: return self.valobj.GetNumChildren() def get_child_index(self, name: str) -> int: - if self.is_ptr and name == "$$dereference$$": - return self.valobj.Dereference().GetSyntheticValue() return self.valobj.GetIndexOfChildWithName(name) def get_child_at_index(self, index: int) -> Optional[SBValue]: @@ -133,13 +131,17 @@ def num_children(self) -> int: return 1 def get_child_index(self, name: str) -> int: - if self.is_ptr and name == "$$dereference$$": + if name == "$$dereference$$": return 0 return -1 def get_child_at_index(self, index: int) -> Optional[SBValue]: if index == 0: - return self.valobj.Dereference().GetSyntheticValue() + value = self.valobj.Dereference() + if (synth := value.GetSyntheticValue()).IsValid(): + return synth + else: + return value return None def update(self): @@ -569,7 +571,9 @@ def update(self): self.variant = all_variants.GetChildAtIndex(index) self.value = self.variant.GetChildMemberWithName( ClangEncodedEnumProvider.VALUE_MEMBER_NAME - ).GetSyntheticValue() + ) + if (synth := self.value.GetSyntheticValue()).IsValid(): + self.value = synth def _getCurrentVariantIndex(self, all_variants: SBValue) -> int: default_index = 0 @@ -651,9 +655,10 @@ def update(self): ).GetValueAsUnsigned() if tag == discr: self.variant = child - self.value = child.GetChildMemberWithName( - "value" - ).GetSyntheticValue() + self.value = child.GetChildMemberWithName("value") + if (synth := self.value.GetSyntheticValue()).IsValid(): + self.value = synth + return else: # if invalid, DISCR must be a range begin: int = ( @@ -671,16 +676,18 @@ def update(self): if begin < end: if begin <= tag <= end: self.variant = child - self.value = child.GetChildMemberWithName( - "value" - ).GetSyntheticValue() + self.value = child.GetChildMemberWithName("value") + if (synth := self.value.GetSyntheticValue()).IsValid(): + self.value = synth + return else: if tag >= begin or tag <= end: self.variant = child - self.value = child.GetChildMemberWithName( - "value" - ).GetSyntheticValue() + self.value = child.GetChildMemberWithName("value") + if (synth := self.value.GetSyntheticValue()).IsValid(): + self.value = synth + return else: # if invalid, tag is a 128 bit value tag_lo: int = self.valobj.GetChildMemberWithName( @@ -714,9 +721,9 @@ def update(self): discr: int = (exact_hi << 64) | exact_lo if tag == discr: self.variant = child - self.value = child.GetChildMemberWithName( - "value" - ).GetSyntheticValue() + self.value = child.GetChildMemberWithName("value") + if (synth := self.value.GetSyntheticValue()).IsValid(): + self.value = synth return else: # if invalid, DISCR must be a range begin_lo: int = ( @@ -748,16 +755,16 @@ def update(self): if begin < end: if begin <= tag <= end: self.variant = child - self.value = child.GetChildMemberWithName( - "value" - ).GetSyntheticValue() + self.value = child.GetChildMemberWithName("value") + if (synth := self.value.GetSyntheticValue()).IsValid(): + self.value = synth return else: if tag >= begin or tag <= end: self.variant = child - self.value = child.GetChildMemberWithName( - "value" - ).GetSyntheticValue() + self.value = child.GetChildMemberWithName("value") + if (synth := self.value.GetSyntheticValue()).IsValid(): + self.value = synth return def num_children(self) -> int: From f69946ac6497495315ff56052d6f41d5532216b9 Mon Sep 17 00:00:00 2001 From: yuk1ty Date: Sat, 21 Mar 2026 23:12:46 +0900 Subject: [PATCH 168/183] Avoid redundant clone suggestions in borrowck diagnostics --- .../src/diagnostics/conflict_errors.rs | 4 +- .../rustc_borrowck/src/diagnostics/mod.rs | 121 ++++++++++++------ .../src/diagnostics/move_errors.rs | 62 +++++---- ...ck-move-out-of-overloaded-auto-deref.fixed | 2 +- ...k-move-out-of-overloaded-auto-deref.stderr | 4 - .../borrowck/clone-span-on-try-operator.fixed | 2 +- .../clone-span-on-try-operator.stderr | 4 - ...move-upvar-from-non-once-ref-closure.fixed | 2 +- ...ove-upvar-from-non-once-ref-closure.stderr | 4 - tests/ui/moves/suggest-clone.fixed | 2 +- tests/ui/moves/suggest-clone.stderr | 4 - .../ui/suggestions/option-content-move.fixed | 4 +- .../ui/suggestions/option-content-move.stderr | 8 -- 13 files changed, 129 insertions(+), 94 deletions(-) diff --git a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs index 2735c800c4a38..639cb75fdd28b 100644 --- a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs @@ -254,7 +254,9 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> { maybe_reinitialized_locations_is_empty: maybe_reinitialized_locations .is_empty(), }; - self.explain_captures( + // The return value indicates whether a clone suggestion was emitted; + // redundancy is already handled via the `FnSelfUse` check below. + let _ = self.explain_captures( &mut err, span, move_span, diff --git a/compiler/rustc_borrowck/src/diagnostics/mod.rs b/compiler/rustc_borrowck/src/diagnostics/mod.rs index a9697950e38be..3ee0369c9da6e 100644 --- a/compiler/rustc_borrowck/src/diagnostics/mod.rs +++ b/compiler/rustc_borrowck/src/diagnostics/mod.rs @@ -1002,6 +1002,12 @@ struct CapturedMessageOpt { maybe_reinitialized_locations_is_empty: bool, } +/// Tracks which suggestions were emitted by [`MirBorrowckCtxt::explain_captures`], +/// so callers can avoid emitting redundant suggestions downstream. +struct ExplainCapturesResult { + clone_suggestion: bool, +} + impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> { /// Finds the spans associated to a move or copy of move_place at location. pub(super) fn move_spans( @@ -1226,7 +1232,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> { move_spans: UseSpans<'tcx>, moved_place: Place<'tcx>, msg_opt: CapturedMessageOpt, - ) { + ) -> ExplainCapturesResult { let CapturedMessageOpt { is_partial_move: is_partial, is_loop_message, @@ -1235,6 +1241,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> { has_suggest_reborrow, maybe_reinitialized_locations_is_empty, } = msg_opt; + let mut suggested_cloning = false; if let UseSpans::FnSelfUse { var_span, fn_call_span, fn_span, kind } = move_spans { let place_name = self .describe_place(moved_place.as_ref()) @@ -1461,10 +1468,26 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> { has_sugg = true; } if let Some(clone_trait) = tcx.lang_items().clone_trait() { - let sugg = if moved_place + // Check whether the deref is from a custom Deref impl + // (e.g. Rc, Box) or a built-in reference deref. + // For built-in derefs with Clone fully satisfied, we skip + // the UFCS suggestion here and let `suggest_cloning` + // downstream emit a simpler `.clone()` suggestion instead. + let has_overloaded_deref = + moved_place.iter_projections().any(|(place, elem)| { + matches!(elem, ProjectionElem::Deref) + && matches!( + self.borrowed_content_source(place), + BorrowedContentSource::OverloadedDeref(_) + | BorrowedContentSource::OverloadedIndex(_) + ) + }); + + let has_deref = moved_place .iter_projections() - .any(|(_, elem)| matches!(elem, ProjectionElem::Deref)) - { + .any(|(_, elem)| matches!(elem, ProjectionElem::Deref)); + + let sugg = if has_deref { let (start, end) = if let Some(expr) = self.find_expr(move_span) && let Some(_) = self.clone_on_reference(expr) && let hir::ExprKind::MethodCall(_, rcvr, _, _) = expr.kind @@ -1490,43 +1513,58 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> { self.infcx.param_env, ) && !has_sugg { - let msg = match &errors[..] { - [] => "you can `clone` the value and consume it, but this \ - might not be your desired behavior" - .to_string(), - [error] => { - format!( - "you could `clone` the value and consume it, if the \ - `{}` trait bound could be satisfied", - error.obligation.predicate, - ) - } - _ => { - format!( - "you could `clone` the value and consume it, if the \ - following trait bounds could be satisfied: {}", - listify(&errors, |e: &FulfillmentError<'tcx>| format!( - "`{}`", - e.obligation.predicate - )) - .unwrap(), - ) - } - }; - err.multipart_suggestion(msg, sugg, Applicability::MaybeIncorrect); - for error in errors { - if let FulfillmentErrorCode::Select( - SelectionError::Unimplemented, - ) = error.code - && let ty::PredicateKind::Clause(ty::ClauseKind::Trait( - pred, - )) = error.obligation.predicate.kind().skip_binder() - { - self.infcx.err_ctxt().suggest_derive( - &error.obligation, - err, - error.obligation.predicate.kind().rebind(pred), - ); + let skip_for_simple_clone = + has_deref && !has_overloaded_deref && errors.is_empty(); + if !skip_for_simple_clone { + let msg = match &errors[..] { + [] => "you can `clone` the value and consume it, but \ + this might not be your desired behavior" + .to_string(), + [error] => { + format!( + "you could `clone` the value and consume it, if \ + the `{}` trait bound could be satisfied", + error.obligation.predicate, + ) + } + _ => { + format!( + "you could `clone` the value and consume it, if \ + the following trait bounds could be satisfied: \ + {}", + listify( + &errors, + |e: &FulfillmentError<'tcx>| format!( + "`{}`", + e.obligation.predicate + ) + ) + .unwrap(), + ) + } + }; + err.multipart_suggestion( + msg, + sugg, + Applicability::MaybeIncorrect, + ); + + suggested_cloning = errors.is_empty(); + + for error in errors { + if let FulfillmentErrorCode::Select( + SelectionError::Unimplemented, + ) = error.code + && let ty::PredicateKind::Clause(ty::ClauseKind::Trait( + pred, + )) = error.obligation.predicate.kind().skip_binder() + { + self.infcx.err_ctxt().suggest_derive( + &error.obligation, + err, + error.obligation.predicate.kind().rebind(pred), + ); + } } } } @@ -1558,6 +1596,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> { }) } } + ExplainCapturesResult { clone_suggestion: suggested_cloning } } /// Skip over locals that begin with an underscore or have no name diff --git a/compiler/rustc_borrowck/src/diagnostics/move_errors.rs b/compiler/rustc_borrowck/src/diagnostics/move_errors.rs index 0d0147e5eb51d..1dfd83956e49b 100644 --- a/compiler/rustc_borrowck/src/diagnostics/move_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/move_errors.rs @@ -269,14 +269,19 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> { .span_delayed_bug(span, "Type may implement copy, but there is no other error."); return; } + + let mut has_clone_suggestion = false; let mut err = match kind { - &IllegalMoveOriginKind::BorrowedContent { target_place } => self - .report_cannot_move_from_borrowed_content( + &IllegalMoveOriginKind::BorrowedContent { target_place } => { + let (diag, clone_sugg) = self.report_cannot_move_from_borrowed_content( original_path, target_place, span, use_spans, - ), + ); + has_clone_suggestion = clone_sugg; + diag + } &IllegalMoveOriginKind::InteriorOfTypeWithDestructor { container_ty: ty } => { self.cannot_move_out_of_interior_of_drop(span, ty) } @@ -285,7 +290,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> { } }; - self.add_move_hints(error, &mut err, span); + self.add_move_hints(error, &mut err, span, has_clone_suggestion); self.buffer_error(err); } @@ -426,7 +431,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> { deref_target_place: Place<'tcx>, span: Span, use_spans: Option>, - ) -> Diag<'infcx> { + ) -> (Diag<'infcx>, bool) { let tcx = self.infcx.tcx; // Inspect the type of the content behind the // borrow to provide feedback about why this @@ -447,8 +452,8 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> { let decl = &self.body.local_decls[local]; let local_name = self.local_name(local).map(|sym| format!("`{sym}`")); if decl.is_ref_for_guard() { - return self - .cannot_move_out_of( + return ( + self.cannot_move_out_of( span, &format!( "{} in pattern guard", @@ -458,9 +463,11 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> { .with_note( "variables bound in patterns cannot be moved from \ until after the end of the pattern guard", - ); + ), + false, + ); } else if decl.is_ref_to_static() { - return self.report_cannot_move_from_static(move_place, span); + return (self.report_cannot_move_from_static(move_place, span), false); } } @@ -539,10 +546,13 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> { has_suggest_reborrow: false, maybe_reinitialized_locations_is_empty: true, }; - if let Some(use_spans) = use_spans { - self.explain_captures(&mut err, span, span, use_spans, move_place, msg_opt); - } - err + let suggested_cloning = if let Some(use_spans) = use_spans { + self.explain_captures(&mut err, span, span, use_spans, move_place, msg_opt) + .clone_suggestion + } else { + false + }; + (err, suggested_cloning) } fn report_closure_move_error( @@ -676,7 +686,13 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> { } } - fn add_move_hints(&self, error: GroupedMoveError<'tcx>, err: &mut Diag<'_>, span: Span) { + fn add_move_hints( + &self, + error: GroupedMoveError<'tcx>, + err: &mut Diag<'_>, + span: Span, + has_clone_suggestion: bool, + ) { match error { GroupedMoveError::MovesFromPlace { mut binds_to, move_from, .. } => { self.add_borrow_suggestions(err, span, !binds_to.is_empty()); @@ -719,14 +735,16 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> { None => "value".to_string(), }; - if let Some(expr) = self.find_expr(use_span) { - self.suggest_cloning( - err, - original_path.as_ref(), - place_ty, - expr, - Some(use_spans), - ); + if !has_clone_suggestion { + if let Some(expr) = self.find_expr(use_span) { + self.suggest_cloning( + err, + original_path.as_ref(), + place_ty, + expr, + Some(use_spans), + ); + } } if let Some(upvar_field) = self diff --git a/tests/ui/borrowck/borrowck-move-out-of-overloaded-auto-deref.fixed b/tests/ui/borrowck/borrowck-move-out-of-overloaded-auto-deref.fixed index a19db7e5cd32a..8d5ebbc774408 100644 --- a/tests/ui/borrowck/borrowck-move-out-of-overloaded-auto-deref.fixed +++ b/tests/ui/borrowck/borrowck-move-out-of-overloaded-auto-deref.fixed @@ -2,6 +2,6 @@ use std::rc::Rc; pub fn main() { - let _x = as Clone>::clone(&Rc::new(vec![1, 2]).clone()).into_iter(); + let _x = as Clone>::clone(&Rc::new(vec![1, 2])).into_iter(); //~^ ERROR [E0507] } diff --git a/tests/ui/borrowck/borrowck-move-out-of-overloaded-auto-deref.stderr b/tests/ui/borrowck/borrowck-move-out-of-overloaded-auto-deref.stderr index 577c2de38be01..076f0ce3440a0 100644 --- a/tests/ui/borrowck/borrowck-move-out-of-overloaded-auto-deref.stderr +++ b/tests/ui/borrowck/borrowck-move-out-of-overloaded-auto-deref.stderr @@ -12,10 +12,6 @@ help: you can `clone` the value and consume it, but this might not be your desir | LL | let _x = as Clone>::clone(&Rc::new(vec![1, 2])).into_iter(); | ++++++++++++++++++++++++++++ + -help: consider cloning the value if the performance cost is acceptable - | -LL | let _x = Rc::new(vec![1, 2]).clone().into_iter(); - | ++++++++ error: aborting due to 1 previous error diff --git a/tests/ui/borrowck/clone-span-on-try-operator.fixed b/tests/ui/borrowck/clone-span-on-try-operator.fixed index 59a162e72c176..86ce083da65e2 100644 --- a/tests/ui/borrowck/clone-span-on-try-operator.fixed +++ b/tests/ui/borrowck/clone-span-on-try-operator.fixed @@ -7,5 +7,5 @@ impl Foo { } fn main() { let foo = &Foo; - ::clone(&foo.clone()).foo(); //~ ERROR cannot move out + foo.clone().foo(); //~ ERROR cannot move out } diff --git a/tests/ui/borrowck/clone-span-on-try-operator.stderr b/tests/ui/borrowck/clone-span-on-try-operator.stderr index c2c63f9494362..4cf1de52a4a47 100644 --- a/tests/ui/borrowck/clone-span-on-try-operator.stderr +++ b/tests/ui/borrowck/clone-span-on-try-operator.stderr @@ -11,10 +11,6 @@ note: `Foo::foo` takes ownership of the receiver `self`, which moves `*foo` | LL | fn foo(self) {} | ^^^^ -help: you can `clone` the value and consume it, but this might not be your desired behavior - | -LL | ::clone(&(*foo)).foo(); - | +++++++++++++++++++++++ + help: consider cloning the value if the performance cost is acceptable | LL - (*foo).foo(); diff --git a/tests/ui/borrowck/unboxed-closures-move-upvar-from-non-once-ref-closure.fixed b/tests/ui/borrowck/unboxed-closures-move-upvar-from-non-once-ref-closure.fixed index 3b4f7c8465cfa..c7ddef0f7bc73 100644 --- a/tests/ui/borrowck/unboxed-closures-move-upvar-from-non-once-ref-closure.fixed +++ b/tests/ui/borrowck/unboxed-closures-move-upvar-from-non-once-ref-closure.fixed @@ -9,7 +9,7 @@ fn call(f: F) where F : Fn() { fn main() { let y = vec![format!("World")]; call(|| { - as Clone>::clone(&y.clone()).into_iter(); + y.clone().into_iter(); //~^ ERROR cannot move out of `y`, a captured variable in an `Fn` closure }); } diff --git a/tests/ui/borrowck/unboxed-closures-move-upvar-from-non-once-ref-closure.stderr b/tests/ui/borrowck/unboxed-closures-move-upvar-from-non-once-ref-closure.stderr index 69c3667491633..08cf528839834 100644 --- a/tests/ui/borrowck/unboxed-closures-move-upvar-from-non-once-ref-closure.stderr +++ b/tests/ui/borrowck/unboxed-closures-move-upvar-from-non-once-ref-closure.stderr @@ -17,10 +17,6 @@ LL | fn call(f: F) where F : Fn() { | ^^^^ note: `into_iter` takes ownership of the receiver `self`, which moves `y` --> $SRC_DIR/core/src/iter/traits/collect.rs:LL:COL -help: you can `clone` the value and consume it, but this might not be your desired behavior - | -LL | as Clone>::clone(&y).into_iter(); - | +++++++++++++++++++++++++++++++ + help: consider cloning the value if the performance cost is acceptable | LL | y.clone().into_iter(); diff --git a/tests/ui/moves/suggest-clone.fixed b/tests/ui/moves/suggest-clone.fixed index 59a162e72c176..86ce083da65e2 100644 --- a/tests/ui/moves/suggest-clone.fixed +++ b/tests/ui/moves/suggest-clone.fixed @@ -7,5 +7,5 @@ impl Foo { } fn main() { let foo = &Foo; - ::clone(&foo.clone()).foo(); //~ ERROR cannot move out + foo.clone().foo(); //~ ERROR cannot move out } diff --git a/tests/ui/moves/suggest-clone.stderr b/tests/ui/moves/suggest-clone.stderr index f8e0ccdfceff0..ec18d2abdec0f 100644 --- a/tests/ui/moves/suggest-clone.stderr +++ b/tests/ui/moves/suggest-clone.stderr @@ -11,10 +11,6 @@ note: `Foo::foo` takes ownership of the receiver `self`, which moves `*foo` | LL | fn foo(self) {} | ^^^^ -help: you can `clone` the value and consume it, but this might not be your desired behavior - | -LL | ::clone(&foo).foo(); - | +++++++++++++++++++++++ + help: consider cloning the value if the performance cost is acceptable | LL | foo.clone().foo(); diff --git a/tests/ui/suggestions/option-content-move.fixed b/tests/ui/suggestions/option-content-move.fixed index 0720146280f90..f36c36d7d645f 100644 --- a/tests/ui/suggestions/option-content-move.fixed +++ b/tests/ui/suggestions/option-content-move.fixed @@ -7,7 +7,7 @@ impl LipogramCorpora { pub fn validate_all(&mut self) -> Result<(), char> { for selection in &self.selections { if selection.1.is_some() { - if as Clone>::clone(&selection.1.clone()).as_mut().as_ref().unwrap().contains(selection.0) { + if selection.1.clone().as_mut().as_ref().unwrap().contains(selection.0) { //~^ ERROR cannot move out of `selection.1` return Err(selection.0); } @@ -25,7 +25,7 @@ impl LipogramCorpora2 { pub fn validate_all(&mut self) -> Result<(), char> { for selection in &self.selections { if selection.1.is_ok() { - if as Clone>::clone(&selection.1.clone()).as_mut().as_ref().unwrap().contains(selection.0) { + if selection.1.clone().as_mut().as_ref().unwrap().contains(selection.0) { //~^ ERROR cannot move out of `selection.1` return Err(selection.0); } diff --git a/tests/ui/suggestions/option-content-move.stderr b/tests/ui/suggestions/option-content-move.stderr index 09c6f39fd803d..b514622699e73 100644 --- a/tests/ui/suggestions/option-content-move.stderr +++ b/tests/ui/suggestions/option-content-move.stderr @@ -16,10 +16,6 @@ help: consider calling `.as_mut()` to mutably borrow the value's contents | LL | if selection.1.as_mut().unwrap().contains(selection.0) { | +++++++++ -help: you can `clone` the value and consume it, but this might not be your desired behavior - | -LL | if as Clone>::clone(&selection.1).unwrap().contains(selection.0) { - | ++++++++++++++++++++++++++++++++++ + help: consider cloning the value if the performance cost is acceptable | LL | if selection.1.clone().unwrap().contains(selection.0) { @@ -43,10 +39,6 @@ help: consider calling `.as_mut()` to mutably borrow the value's contents | LL | if selection.1.as_mut().unwrap().contains(selection.0) { | +++++++++ -help: you can `clone` the value and consume it, but this might not be your desired behavior - | -LL | if as Clone>::clone(&selection.1).unwrap().contains(selection.0) { - | ++++++++++++++++++++++++++++++++++++++++++ + help: consider cloning the value if the performance cost is acceptable | LL | if selection.1.clone().unwrap().contains(selection.0) { From 180bfeffdb6cd79c76535286b64789e54602997a Mon Sep 17 00:00:00 2001 From: Walnut <39544927+Walnut356@users.noreply.github.com> Date: Fri, 24 Apr 2026 09:08:05 -0500 Subject: [PATCH 169/183] Pass fields to `is_tuple_fields` instead of `SBValue` object --- src/etc/lldb_providers.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/etc/lldb_providers.py b/src/etc/lldb_providers.py index ef3f94ee83530..d84807687f2c2 100644 --- a/src/etc/lldb_providers.py +++ b/src/etc/lldb_providers.py @@ -266,7 +266,7 @@ def aggregate_field_summary(valobj: SBValue, _dict) -> Generator[str, None, None if summary is None: summary = child.value if summary is None: - if is_tuple_fields(child): + if is_tuple_fields(child.GetType().fields): summary = TupleSummaryProvider(child, _dict) else: summary = StructSummaryProvider(child, _dict) From 15e60ebe6e58ba13dcf2d2720889de8a0c9d6cf9 Mon Sep 17 00:00:00 2001 From: xtqqczze <45661989+xtqqczze@users.noreply.github.com> Date: Fri, 24 Apr 2026 15:19:36 +0100 Subject: [PATCH 170/183] std: Refactor flush method in BufWriter to use the `?` operator --- library/std/src/io/buffered/bufwriter.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/library/std/src/io/buffered/bufwriter.rs b/library/std/src/io/buffered/bufwriter.rs index d569fed24c561..1b34724e6ccdb 100644 --- a/library/std/src/io/buffered/bufwriter.rs +++ b/library/std/src/io/buffered/bufwriter.rs @@ -641,7 +641,8 @@ impl Write for BufWriter { } fn flush(&mut self) -> io::Result<()> { - self.flush_buf().and_then(|()| self.get_mut().flush()) + self.flush_buf()?; + self.get_mut().flush() } } From c2916be8d78ae46a29b56806a55fdf0a14f4cee9 Mon Sep 17 00:00:00 2001 From: mejrs <59372212+mejrs@users.noreply.github.com> Date: Thu, 23 Apr 2026 21:59:41 +0200 Subject: [PATCH 171/183] Permit `{This}` in diagnostic attribute format literals --- .../src/attributes/diagnostic/mod.rs | 126 ++++++++++++------ compiler/rustc_attr_parsing/src/errors.rs | 48 ++++--- compiler/rustc_hir/src/lints.rs | 2 +- compiler/rustc_lint_defs/src/lib.rs | 7 - compiler/rustc_passes/src/check_attr.rs | 18 +-- compiler/rustc_passes/src/errors.rs | 7 - compiler/rustc_resolve/src/imports.rs | 9 +- .../traits/on_unimplemented.rs | 1 - .../diagnostic_namespace/multiline_spans.rs | 8 +- .../multiline_spans.stderr | 24 ++-- .../on_move/on_move_with_format.rs | 5 + .../on_move/on_move_with_format.stderr | 15 ++- .../on_unimplemented/broken_format.rs | 12 +- .../on_unimplemented/broken_format.stderr | 36 ++--- .../on_unknown/incorrect_format_string.rs | 19 +-- .../on_unknown/incorrect_format_string.stderr | 72 ++++++---- .../on_unknown/this_format_argument.rs | 45 +++++++ .../on_unknown/this_format_argument.stderr | 60 +++++++++ .../on_unknown/unknown_import.rs | 2 +- .../report_warning_on_invalid_formats.rs | 5 +- .../report_warning_on_invalid_formats.stderr | 6 +- tests/ui/on-unimplemented/bad-annotation.rs | 3 +- .../ui/on-unimplemented/bad-annotation.stderr | 42 +++--- 23 files changed, 368 insertions(+), 204 deletions(-) create mode 100644 tests/ui/diagnostic_namespace/on_unknown/this_format_argument.rs create mode 100644 tests/ui/diagnostic_namespace/on_unknown/this_format_argument.stderr diff --git a/compiler/rustc_attr_parsing/src/attributes/diagnostic/mod.rs b/compiler/rustc_attr_parsing/src/attributes/diagnostic/mod.rs index 53491a0a959ac..ee99e2904c80d 100644 --- a/compiler/rustc_attr_parsing/src/attributes/diagnostic/mod.rs +++ b/compiler/rustc_attr_parsing/src/attributes/diagnostic/mod.rs @@ -6,7 +6,6 @@ use rustc_hir::attrs::diagnostic::{ Directive, FilterFormatString, Flag, FormatArg, FormatString, LitOrArg, Name, NameValue, OnUnimplementedCondition, Piece, Predicate, }; -use rustc_hir::lints::FormatWarning; use rustc_macros::Diagnostic; use rustc_parse_format::{ Argument, FormatSpec, ParseError, ParseMode, Parser, Piece as RpfPiece, Position, @@ -19,9 +18,8 @@ use thin_vec::{ThinVec, thin_vec}; use crate::context::{AcceptContext, Stage}; use crate::errors::{ - DisallowedPlaceholder, DisallowedPositionalArgument, IgnoredDiagnosticOption, - InvalidFormatSpecifier, MalFormedDiagnosticAttributeLint, MissingOptionsForDiagnosticAttribute, - NonMetaItemDiagnosticAttribute, WrappedParserError, + FormatWarning, IgnoredDiagnosticOption, MalFormedDiagnosticAttributeLint, + MissingOptionsForDiagnosticAttribute, NonMetaItemDiagnosticAttribute, WrappedParserError, }; use crate::parser::{ArgParser, MetaItemListParser, MetaItemOrLitParser, MetaItemParser}; @@ -88,6 +86,29 @@ impl Mode { Self::DiagnosticOnUnmatchArgs => DEFAULT, } } + + fn allowed_format_arguments(&self) -> &'static str { + match self { + Self::RustcOnUnimplemented => { + "see for allowed format arguments" + } + Self::DiagnosticOnUnimplemented => { + "only `Self` and generics of the trait are allowed as a format argument" + } + Self::DiagnosticOnConst => { + "only `Self` and generics of the implementation are allowed as a format argument" + } + Self::DiagnosticOnMove => { + "only `This`, `Self` and generics of the type are allowed as a format argument" + } + Self::DiagnosticOnUnknown => { + "only `This` is allowed as a format argument, referring to the failed import" + } + Self::DiagnosticOnUnmatchArgs => { + "only `This` is allowed as a format argument, referring to the macro's name" + } + } + } } fn merge_directives( @@ -257,22 +278,13 @@ fn parse_directive_items<'p, S: Stage>( match parse_format_string(input.name, snippet, input.span, mode) { Ok((f, warnings)) => { for warning in warnings { - let (FormatWarning::InvalidSpecifier { span, .. } - | FormatWarning::PositionalArgument { span, .. } - | FormatWarning::DisallowedPlaceholder { span }) = warning; + let (FormatWarning::InvalidSpecifier { span } + | FormatWarning::PositionalArgument { span } + | FormatWarning::IndexedArgument { span } + | FormatWarning::DisallowedPlaceholder { span, .. }) = warning; cx.emit_dyn_lint( MALFORMED_DIAGNOSTIC_FORMAT_LITERALS, - move |dcx, level| match warning { - FormatWarning::PositionalArgument { .. } => { - DisallowedPositionalArgument.into_diag(dcx, level) - } - FormatWarning::InvalidSpecifier { .. } => { - InvalidFormatSpecifier.into_diag(dcx, level) - } - FormatWarning::DisallowedPlaceholder { .. } => { - DisallowedPlaceholder.into_diag(dcx, level) - } - }, + move |dcx, level| warning.into_diag(dcx, level), span, ); } @@ -422,38 +434,74 @@ fn parse_arg( is_source_literal: bool, ) -> FormatArg { let span = slice_span(input_span, arg.position_span.clone(), is_source_literal); - if matches!(mode, Mode::DiagnosticOnUnknown) { - warnings.push(FormatWarning::DisallowedPlaceholder { span }); - return FormatArg::AsIs(sym::empty_braces); - } match arg.position { // Something like "hello {name}" Position::ArgumentNamed(name) => match (mode, Symbol::intern(name)) { - // Only `#[rustc_on_unimplemented]` can use these - (Mode::RustcOnUnimplemented { .. }, sym::ItemContext) => FormatArg::ItemContext, - (Mode::RustcOnUnimplemented { .. } | Mode::DiagnosticOnUnmatchArgs, sym::This) => { - FormatArg::This + (Mode::RustcOnUnimplemented, sym::ItemContext) => FormatArg::ItemContext, + + // Like `{This}`, but sugared. + // FIXME(mejrs) maybe rename/rework this or something + // if we want to apply this to other attrs? + (Mode::RustcOnUnimplemented, sym::Trait) => FormatArg::Trait, + + // Some diagnostic attributes can use `{This}` to refer to the annotated item. + // For those that don't, we continue and maybe use it as a generic parameter. + // + // FIXME(mejrs) `DiagnosticOnUnimplemented` is intentionally not here; + // that requires lang approval which is best kept for a standalone PR. + ( + Mode::RustcOnUnimplemented + | Mode::DiagnosticOnUnknown + | Mode::DiagnosticOnMove + | Mode::DiagnosticOnUnmatchArgs, + sym::This, + ) => FormatArg::This, + + // `{Self}`; the self type. + // - For trait declaration attributes that's the type that does not implement it. + // - for trait impl attributes, the implemented for type. + // - For ADT attributes, that's the type (which will be identical to `{This}`) + // - For everything else it doesn't make sense. + ( + Mode::RustcOnUnimplemented + | Mode::DiagnosticOnUnimplemented + | Mode::DiagnosticOnMove + | Mode::DiagnosticOnConst, + kw::SelfUpper, + ) => FormatArg::SelfUpper, + + // Generic parameters. + // FIXME(mejrs) unfortunately, all the "special" symbols above might fall through, + // but at this time we are not aware of what generic parameters the trait actually has. + // If we find `ItemContext` or something we have to assume that's a generic parameter. + // We lint against that in `check_attr.rs` though. + ( + Mode::RustcOnUnimplemented + | Mode::DiagnosticOnUnimplemented + | Mode::DiagnosticOnMove + | Mode::DiagnosticOnConst, + generic_param, + ) => FormatArg::GenericParam { generic_param, span }, + + // Generics are explicitly not allowed, we print those back as is. + (Mode::DiagnosticOnUnknown | Mode::DiagnosticOnUnmatchArgs, as_is) => { + warnings.push(FormatWarning::DisallowedPlaceholder { + span, + attr: mode.as_str(), + allowed: mode.allowed_format_arguments(), + }); + return FormatArg::AsIs(Symbol::intern(&format!("{{{as_is}}}"))); } - (Mode::RustcOnUnimplemented { .. }, sym::Trait) => FormatArg::Trait, - // Any attribute can use these - (_, kw::SelfUpper) => FormatArg::SelfUpper, - (_, generic_param) => FormatArg::GenericParam { generic_param, span }, }, // `{:1}` and `{}` are ignored Position::ArgumentIs(idx) => { - warnings.push(FormatWarning::PositionalArgument { - span, - help: format!("use `{{{idx}}}` to print a number in braces"), - }); + warnings.push(FormatWarning::IndexedArgument { span }); FormatArg::AsIs(Symbol::intern(&format!("{{{idx}}}"))) } Position::ArgumentImplicitlyIs(_) => { - warnings.push(FormatWarning::PositionalArgument { - span, - help: String::from("use `{{}}` to print empty braces"), - }); + warnings.push(FormatWarning::PositionalArgument { span }); FormatArg::AsIs(sym::empty_braces) } } @@ -473,7 +521,7 @@ fn warn_on_format_spec( .as_ref() .map(|inner| slice_span(input_span, inner.clone(), is_source_literal)) .unwrap_or(input_span); - warnings.push(FormatWarning::InvalidSpecifier { span, name: spec.ty.into() }) + warnings.push(FormatWarning::InvalidSpecifier { span }) } } diff --git a/compiler/rustc_attr_parsing/src/errors.rs b/compiler/rustc_attr_parsing/src/errors.rs index 95d0e82f472c0..e35f73de35ec0 100644 --- a/compiler/rustc_attr_parsing/src/errors.rs +++ b/compiler/rustc_attr_parsing/src/errors.rs @@ -357,23 +357,6 @@ pub(crate) struct MalFormedDiagnosticAttributeLint { pub span: Span, } -#[derive(Diagnostic)] -#[diag("positional format arguments are not allowed here")] -#[help( - "only named format arguments with the name of one of the generic types are allowed in this context" -)] -pub(crate) struct DisallowedPositionalArgument; - -#[derive(Diagnostic)] -#[diag("format arguments are not allowed here")] -#[help("consider removing this format argument")] -pub(crate) struct DisallowedPlaceholder; - -#[derive(Diagnostic)] -#[diag("invalid format specifier")] -#[help("no format specifier are supported in this position")] -pub(crate) struct InvalidFormatSpecifier; - #[derive(Diagnostic)] #[diag("{$description}")] pub(crate) struct WrappedParserError<'a> { @@ -407,3 +390,34 @@ pub(crate) struct MissingOptionsForDiagnosticAttribute { "only literals are allowed as values for the `message`, `note` and `label` options. These options must be separated by a comma" )] pub(crate) struct NonMetaItemDiagnosticAttribute; + +#[derive(Diagnostic, Clone, Copy)] +pub(crate) enum FormatWarning { + #[diag("positional arguments are not permitted in diagnostic attributes")] + #[help("you can print empty braces by escaping them")] + PositionalArgument { + #[label("remove this format argument")] + span: Span, + }, + + #[diag("indexed format arguments are not permitted in diagnostic attributes")] + IndexedArgument { + #[label("remove this format argument")] + span: Span, + }, + + #[diag("format specifiers are not permitted in diagnostic attributes")] + InvalidSpecifier { + #[label("remove this format specifier")] + span: Span, + }, + + #[diag("this format argument is not allowed in `#[{$attr}]`")] + #[note("{$allowed}")] + DisallowedPlaceholder { + #[label("remove this format argument")] + span: Span, + attr: &'static str, + allowed: &'static str, + }, +} diff --git a/compiler/rustc_hir/src/lints.rs b/compiler/rustc_hir/src/lints.rs index d7bd9f874dd22..cdafca37a504a 100644 --- a/compiler/rustc_hir/src/lints.rs +++ b/compiler/rustc_hir/src/lints.rs @@ -1,8 +1,8 @@ use rustc_data_structures::sync::{DynSend, DynSync}; use rustc_error_messages::MultiSpan; use rustc_errors::{Diag, DiagCtxtHandle, Level}; +pub use rustc_lint_defs::AttributeLintKind; use rustc_lint_defs::LintId; -pub use rustc_lint_defs::{AttributeLintKind, FormatWarning}; use crate::HirId; diff --git a/compiler/rustc_lint_defs/src/lib.rs b/compiler/rustc_lint_defs/src/lib.rs index 0a9c0669a5bd3..8cbd2456fccd0 100644 --- a/compiler/rustc_lint_defs/src/lib.rs +++ b/compiler/rustc_lint_defs/src/lib.rs @@ -658,13 +658,6 @@ pub enum AttributeLintKind { UnexpectedCfgValue((Symbol, Span), Option<(Symbol, Span)>), } -#[derive(Debug, Clone, HashStable_Generic)] -pub enum FormatWarning { - PositionalArgument { span: Span, help: String }, - InvalidSpecifier { name: String, span: Span }, - DisallowedPlaceholder { span: Span }, -} - pub type RegisteredTools = FxIndexSet; /// Declares a static item of type `&'static Lint`. diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs index d11825016baf3..ebf0f06f7173d 100644 --- a/compiler/rustc_passes/src/check_attr.rs +++ b/compiler/rustc_passes/src/check_attr.rs @@ -201,9 +201,6 @@ impl<'tcx> CheckAttrVisitor<'tcx> { }, Attribute::Parsed(AttributeKind::OnUnimplemented{directive,..}) => {self.check_diagnostic_on_unimplemented(hir_id, directive.as_deref())}, Attribute::Parsed(AttributeKind::OnConst{span, ..}) => {self.check_diagnostic_on_const(*span, hir_id, target, item)}, - Attribute::Parsed(AttributeKind::OnUnmatchArgs { directive, .. }) => { - self.check_diagnostic_on_unmatch_args(hir_id, directive.as_deref()) - }, Attribute::Parsed(AttributeKind::OnMove { directive , .. }) => { self.check_diagnostic_on_move(hir_id, directive.as_deref()) }, @@ -256,6 +253,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { | AttributeKind::NoMangle(..) | AttributeKind::NoStd { .. } | AttributeKind::OnUnknown { .. } + | AttributeKind::OnUnmatchArgs { .. } | AttributeKind::Optimize(..) | AttributeKind::PanicRuntime | AttributeKind::PatchableFunctionEntry { .. } @@ -562,20 +560,6 @@ impl<'tcx> CheckAttrVisitor<'tcx> { // ...whose generics would that be, anyway? The traits' or the impls'? } - /// Checks use of generic formatting parameters in `#[diagnostic::on_unmatch_args]`. - fn check_diagnostic_on_unmatch_args(&self, hir_id: HirId, directive: Option<&Directive>) { - if let Some(directive) = directive { - directive.visit_params(&mut |argument_name, span| { - self.tcx.emit_node_span_lint( - MALFORMED_DIAGNOSTIC_FORMAT_LITERALS, - hir_id, - span, - errors::OnUnmatchArgsMalformedFormatLiterals { name: argument_name }, - ) - }); - } - } - /// Checks use of generic formatting parameters in `#[diagnostic::on_move]` fn check_diagnostic_on_move(&self, hir_id: HirId, directive: Option<&Directive>) { if let Some(directive) = directive { diff --git a/compiler/rustc_passes/src/errors.rs b/compiler/rustc_passes/src/errors.rs index 5300267573e62..a916b4670fded 100644 --- a/compiler/rustc_passes/src/errors.rs +++ b/compiler/rustc_passes/src/errors.rs @@ -1303,10 +1303,3 @@ pub(crate) struct UnknownFormatParameterForOnUnimplementedAttr { pub(crate) struct OnMoveMalformedFormatLiterals { pub name: Symbol, } - -#[derive(Diagnostic)] -#[diag("unknown parameter `{$name}`")] -#[help(r#"use {"`{This}`"} to refer to the macro name"#)] -pub(crate) struct OnUnmatchArgsMalformedFormatLiterals { - pub name: Symbol, -} diff --git a/compiler/rustc_resolve/src/imports.rs b/compiler/rustc_resolve/src/imports.rs index 4cb9a653e010a..d8ab279ef7a98 100644 --- a/compiler/rustc_resolve/src/imports.rs +++ b/compiler/rustc_resolve/src/imports.rs @@ -2,6 +2,7 @@ use std::mem; +use itertools::Itertools; use rustc_ast::{Item, NodeId}; use rustc_attr_parsing::AttributeParser; use rustc_data_structures::fx::{FxHashSet, FxIndexSet}; @@ -879,8 +880,14 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { let (message, label, notes) = // Feature gating for `on_unknown_attr` happens initialization of the field if let Some(directive) = errors[0].1.on_unknown_attr.as_ref().map(|a| &a.directive) { + let this = errors.iter().map(|(_import, err)| { + + // Is this unwrap_or reachable? + err.segment.unwrap_or(kw::Underscore) + }).join(", "); + let args = FormatArgs { - this: paths.join(", "), + this, // Unused this_sugared: String::new(), // Unused diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/on_unimplemented.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/on_unimplemented.rs index b6ea4ddc63248..a65e612b93e9c 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/traits/on_unimplemented.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/traits/on_unimplemented.rs @@ -4,7 +4,6 @@ use rustc_hir as hir; use rustc_hir::attrs::diagnostic::{ConditionOptions, CustomDiagnostic, FormatArgs}; use rustc_hir::def_id::LocalDefId; use rustc_hir::find_attr; -pub use rustc_hir::lints::FormatWarning; use rustc_middle::ty::print::PrintTraitRefExt; use rustc_middle::ty::{self, GenericParamDef, GenericParamDefKind}; use rustc_span::Symbol; diff --git a/tests/ui/diagnostic_namespace/multiline_spans.rs b/tests/ui/diagnostic_namespace/multiline_spans.rs index e0876b19df07f..09aba104806fb 100644 --- a/tests/ui/diagnostic_namespace/multiline_spans.rs +++ b/tests/ui/diagnostic_namespace/multiline_spans.rs @@ -31,17 +31,17 @@ pub trait MultiLine4 {} #[diagnostic::on_unimplemented(message = "here is a big \ multiline string \ {Self:+}")] -//~^ ERROR invalid format specifier [malformed_diagnostic_format_literals] +//~^ ERROR format specifiers are not permitted in diagnostic attributes [malformed_diagnostic_format_literals] pub trait MultiLineFmt {} #[diagnostic::on_unimplemented(message = "here is a big \ multiline string {Self:X}")] -//~^ ERROR invalid format specifier [malformed_diagnostic_format_literals] +//~^ ERROR format specifiers are not permitted in diagnostic attributes [malformed_diagnostic_format_literals] pub trait MultiLineFmt2 {} #[diagnostic::on_unimplemented(message = "here is a big \ multiline string {Self:#}")] -//~^ ERROR invalid format specifier [malformed_diagnostic_format_literals] +//~^ ERROR format specifiers are not permitted in diagnostic attributes [malformed_diagnostic_format_literals] pub trait MultiLineFmt3 {} @@ -51,5 +51,5 @@ pub trait MultiLineFmt3 {} \ \ multiline string {Self:?}")] -//~^ ERROR invalid format specifier [malformed_diagnostic_format_literals] +//~^ ERROR format specifiers are not permitted in diagnostic attributes [malformed_diagnostic_format_literals] pub trait MultiLineFmt4 {} diff --git a/tests/ui/diagnostic_namespace/multiline_spans.stderr b/tests/ui/diagnostic_namespace/multiline_spans.stderr index 0e4bb864b9655..e5cfcfd183944 100644 --- a/tests/ui/diagnostic_namespace/multiline_spans.stderr +++ b/tests/ui/diagnostic_namespace/multiline_spans.stderr @@ -36,37 +36,29 @@ LL | multiline string {unknown}")] | = help: expect either a generic argument name or `{Self}` as format argument -error: invalid format specifier +error: format specifiers are not permitted in diagnostic attributes --> $DIR/multiline_spans.rs:33:47 | LL | ... {Self:+}")] - | ^^ - | - = help: no format specifier are supported in this position + | ^^ remove this format specifier -error: invalid format specifier +error: format specifiers are not permitted in diagnostic attributes --> $DIR/multiline_spans.rs:38:64 | LL | ... multiline string {Self:X}")] - | ^^ - | - = help: no format specifier are supported in this position + | ^^ remove this format specifier -error: invalid format specifier +error: format specifiers are not permitted in diagnostic attributes --> $DIR/multiline_spans.rs:43:27 | LL | multiline string {Self:#}")] - | ^^ - | - = help: no format specifier are supported in this position + | ^^ remove this format specifier -error: invalid format specifier +error: format specifiers are not permitted in diagnostic attributes --> $DIR/multiline_spans.rs:53:27 | LL | multiline string {Self:?}")] - | ^^ - | - = help: no format specifier are supported in this position + | ^^ remove this format specifier error: aborting due to 8 previous errors diff --git a/tests/ui/diagnostic_namespace/on_move/on_move_with_format.rs b/tests/ui/diagnostic_namespace/on_move/on_move_with_format.rs index f2025c2b2271b..54035d1d0ea67 100644 --- a/tests/ui/diagnostic_namespace/on_move/on_move_with_format.rs +++ b/tests/ui/diagnostic_namespace/on_move/on_move_with_format.rs @@ -1,3 +1,4 @@ +//@ dont-require-annotations: NOTE #![feature(diagnostic_on_move)] #[diagnostic::on_move( @@ -10,6 +11,7 @@ struct Foo; #[diagnostic::on_move( message="Foo for {X}", label="Bar for {X}", + note = "This is `{This}`", )] struct MyType { _x: X, @@ -21,12 +23,15 @@ fn takes_mytype(_: MyType) {} fn main() { let foo = Foo; + //~^ NOTE Bar for Foo takes_foo(foo); let bar = foo; //~^ERROR Foo for Foo let mytype = MyType { _x: 0 }; + //~^ NOTE Bar for i32 takes_mytype(mytype); let baz = mytype; //~^ERROR Foo for i32 + //~|NOTE This is `MyType` } diff --git a/tests/ui/diagnostic_namespace/on_move/on_move_with_format.stderr b/tests/ui/diagnostic_namespace/on_move/on_move_with_format.stderr index 6868f1571be8f..821a502dbcd68 100644 --- a/tests/ui/diagnostic_namespace/on_move/on_move_with_format.stderr +++ b/tests/ui/diagnostic_namespace/on_move/on_move_with_format.stderr @@ -1,22 +1,23 @@ error[E0382]: Foo for Foo - --> $DIR/on_move_with_format.rs:25:15 + --> $DIR/on_move_with_format.rs:28:15 | LL | let foo = Foo; | --- Bar for Foo +LL | LL | takes_foo(foo); | --- value moved here LL | let bar = foo; | ^^^ value used here after move | note: consider changing this parameter type in function `takes_foo` to borrow instead if owning the value isn't necessary - --> $DIR/on_move_with_format.rs:18:17 + --> $DIR/on_move_with_format.rs:20:17 | LL | fn takes_foo(_: Foo) {} | --------- ^^^ this parameter takes ownership of the value | | | in this function note: if `Foo` implemented `Clone`, you could clone the value - --> $DIR/on_move_with_format.rs:8:1 + --> $DIR/on_move_with_format.rs:9:1 | LL | struct Foo; | ^^^^^^^^^^ consider implementing `Clone` for this type @@ -25,24 +26,26 @@ LL | takes_foo(foo); | --- you could clone this value error[E0382]: Foo for i32 - --> $DIR/on_move_with_format.rs:30:15 + --> $DIR/on_move_with_format.rs:34:15 | LL | let mytype = MyType { _x: 0 }; | ------ Bar for i32 +LL | LL | takes_mytype(mytype); | ------ value moved here LL | let baz = mytype; | ^^^^^^ value used here after move | + = note: This is `MyType` note: consider changing this parameter type in function `takes_mytype` to borrow instead if owning the value isn't necessary - --> $DIR/on_move_with_format.rs:20:23 + --> $DIR/on_move_with_format.rs:22:23 | LL | fn takes_mytype(_: MyType) {} | ------------ ^^^^^^^^^ this parameter takes ownership of the value | | | in this function note: if `MyType` implemented `Clone`, you could clone the value - --> $DIR/on_move_with_format.rs:14:1 + --> $DIR/on_move_with_format.rs:16:1 | LL | struct MyType { | ^^^^^^^^^^^^^^^^ consider implementing `Clone` for this type diff --git a/tests/ui/diagnostic_namespace/on_unimplemented/broken_format.rs b/tests/ui/diagnostic_namespace/on_unimplemented/broken_format.rs index 56255a25b3f39..640115765fd6e 100644 --- a/tests/ui/diagnostic_namespace/on_unimplemented/broken_format.rs +++ b/tests/ui/diagnostic_namespace/on_unimplemented/broken_format.rs @@ -4,24 +4,24 @@ trait ImportantTrait1 {} #[diagnostic::on_unimplemented(message = "Test {}")] -//~^WARN positional format arguments are not allowed here +//~^WARN positional arguments are not permitted in diagnostic attributes trait ImportantTrait2 {} #[diagnostic::on_unimplemented(message = "Test {1:}")] -//~^WARN positional format arguments are not allowed here -//~|WARN invalid format specifier [malformed_diagnostic_format_literals] +//~^WARN indexed format arguments are not permitted in diagnostic attributes +//~|WARN format specifiers are not permitted in diagnostic attributes [malformed_diagnostic_format_literals] trait ImportantTrait3 {} #[diagnostic::on_unimplemented(message = "Test {Self:123}")] -//~^WARN invalid format specifier +//~^WARN format specifiers are not permitted in diagnostic attributes trait ImportantTrait4 {} #[diagnostic::on_unimplemented(message = "Test {Self:!}")] -//~^WARN invalid format specifier [malformed_diagnostic_format_literals] +//~^WARN format specifiers are not permitted in diagnostic attributes [malformed_diagnostic_format_literals] trait ImportantTrait5 {} #[diagnostic::on_unimplemented(message = "Test {Self:}")] -//~^WARN invalid format specifier [malformed_diagnostic_format_literals] +//~^WARN format specifiers are not permitted in diagnostic attributes [malformed_diagnostic_format_literals] trait ImportantTrait6 {} diff --git a/tests/ui/diagnostic_namespace/on_unimplemented/broken_format.stderr b/tests/ui/diagnostic_namespace/on_unimplemented/broken_format.stderr index a6ab2f245a3e4..983f871dde109 100644 --- a/tests/ui/diagnostic_namespace/on_unimplemented/broken_format.stderr +++ b/tests/ui/diagnostic_namespace/on_unimplemented/broken_format.stderr @@ -8,53 +8,43 @@ LL | #[diagnostic::on_unimplemented(message = "{{Test } thing")] | = note: `#[warn(malformed_diagnostic_format_literals)]` (part of `#[warn(unknown_or_malformed_diagnostic_attributes)]`) on by default -warning: positional format arguments are not allowed here +warning: positional arguments are not permitted in diagnostic attributes --> $DIR/broken_format.rs:6:49 | LL | #[diagnostic::on_unimplemented(message = "Test {}")] - | ^ + | ^ remove this format argument | - = help: only named format arguments with the name of one of the generic types are allowed in this context + = help: you can print empty braces by escaping them -warning: invalid format specifier +warning: format specifiers are not permitted in diagnostic attributes --> $DIR/broken_format.rs:10:50 | LL | #[diagnostic::on_unimplemented(message = "Test {1:}")] - | ^ - | - = help: no format specifier are supported in this position + | ^ remove this format specifier -warning: positional format arguments are not allowed here +warning: indexed format arguments are not permitted in diagnostic attributes --> $DIR/broken_format.rs:10:49 | LL | #[diagnostic::on_unimplemented(message = "Test {1:}")] - | ^ - | - = help: only named format arguments with the name of one of the generic types are allowed in this context + | ^ remove this format argument -warning: invalid format specifier +warning: format specifiers are not permitted in diagnostic attributes --> $DIR/broken_format.rs:15:53 | LL | #[diagnostic::on_unimplemented(message = "Test {Self:123}")] - | ^^^^ - | - = help: no format specifier are supported in this position + | ^^^^ remove this format specifier -warning: invalid format specifier +warning: format specifiers are not permitted in diagnostic attributes --> $DIR/broken_format.rs:19:53 | LL | #[diagnostic::on_unimplemented(message = "Test {Self:!}")] - | ^^ - | - = help: no format specifier are supported in this position + | ^^ remove this format specifier -warning: invalid format specifier +warning: format specifiers are not permitted in diagnostic attributes --> $DIR/broken_format.rs:23:53 | LL | #[diagnostic::on_unimplemented(message = "Test {Self:}")] - | ^ - | - = help: no format specifier are supported in this position + | ^ remove this format specifier error[E0277]: {{Test } thing --> $DIR/broken_format.rs:36:13 diff --git a/tests/ui/diagnostic_namespace/on_unknown/incorrect_format_string.rs b/tests/ui/diagnostic_namespace/on_unknown/incorrect_format_string.rs index cdf0f1e89efc1..82fcf11712db9 100644 --- a/tests/ui/diagnostic_namespace/on_unknown/incorrect_format_string.rs +++ b/tests/ui/diagnostic_namespace/on_unknown/incorrect_format_string.rs @@ -1,32 +1,35 @@ #![feature(diagnostic_on_unknown)] #[diagnostic::on_unknown(message = "foo {}")] -//~^ WARN: format arguments are not allowed here +//~^ WARN: positional arguments are not permitted in diagnostic attributes use std::does_not_exist; //~^ ERROR: foo {} #[diagnostic::on_unknown(message = "foo {A}")] -//~^ WARN: format arguments are not allowed here +//~^ WARN: this format argument is not allowed in `#[diagnostic::on_unknown]` use std::does_not_exist2; -//~^ ERROR: foo {} +//~^ ERROR: foo {A} #[diagnostic::on_unknown(label = "foo {}")] -//~^ WARN: format arguments are not allowed here +//~^ WARN: positional arguments are not permitted in diagnostic attributes use std::does_not_exist3; //~^ ERROR: unresolved import `std::does_not_exist3` #[diagnostic::on_unknown(label = "foo {A}")] -//~^ WARN: format arguments are not allowed here +//~^ WARN: this format argument is not allowed in `#[diagnostic::on_unknown]` use std::does_not_exist4; //~^ ERROR: unresolved import `std::does_not_exist4` #[diagnostic::on_unknown(note = "foo {}")] -//~^ WARN: format arguments are not allowed here +//~^ WARN: positional arguments are not permitted in diagnostic attributes use std::does_not_exist5; //~^ ERROR: unresolved import `std::does_not_exist5` -#[diagnostic::on_unknown(note = "foo {A}")] -//~^ WARN: format arguments are not allowed here +#[diagnostic::on_unknown(note = "foo {Self} {ItemContext} {Trait} {A}")] +//~^ WARN: this format argument is not allowed in `#[diagnostic::on_unknown]` +//~| WARN: this format argument is not allowed in `#[diagnostic::on_unknown]` +//~| WARN: this format argument is not allowed in `#[diagnostic::on_unknown]` +//~| WARN: this format argument is not allowed in `#[diagnostic::on_unknown]` use std::does_not_exist6; //~^ ERROR: unresolved import `std::does_not_exist6` diff --git a/tests/ui/diagnostic_namespace/on_unknown/incorrect_format_string.stderr b/tests/ui/diagnostic_namespace/on_unknown/incorrect_format_string.stderr index 2b942338ffb4e..9c2d5b0269f87 100644 --- a/tests/ui/diagnostic_namespace/on_unknown/incorrect_format_string.stderr +++ b/tests/ui/diagnostic_namespace/on_unknown/incorrect_format_string.stderr @@ -6,7 +6,7 @@ LL | use std::does_not_exist; | = note: unresolved import `std::does_not_exist` -error[E0432]: foo {} +error[E0432]: foo {A} --> $DIR/incorrect_format_string.rs:10:5 | LL | use std::does_not_exist2; @@ -24,7 +24,7 @@ error[E0432]: unresolved import `std::does_not_exist4` --> $DIR/incorrect_format_string.rs:20:5 | LL | use std::does_not_exist4; - | ^^^^^^^^^^^^^^^^^^^^ foo {} + | ^^^^^^^^^^^^^^^^^^^^ foo {A} error[E0432]: unresolved import `std::does_not_exist5` --> $DIR/incorrect_format_string.rs:25:5 @@ -35,62 +35,86 @@ LL | use std::does_not_exist5; = note: foo {} error[E0432]: unresolved import `std::does_not_exist6` - --> $DIR/incorrect_format_string.rs:30:5 + --> $DIR/incorrect_format_string.rs:33:5 | LL | use std::does_not_exist6; | ^^^^^^^^^^^^^^^^^^^^ no `does_not_exist6` in the root | - = note: foo {} + = note: foo {Self} {ItemContext} {Trait} {A} -warning: format arguments are not allowed here +warning: positional arguments are not permitted in diagnostic attributes --> $DIR/incorrect_format_string.rs:3:42 | LL | #[diagnostic::on_unknown(message = "foo {}")] - | ^ + | ^ remove this format argument | - = help: consider removing this format argument + = help: you can print empty braces by escaping them = note: `#[warn(malformed_diagnostic_format_literals)]` (part of `#[warn(unknown_or_malformed_diagnostic_attributes)]`) on by default -warning: format arguments are not allowed here +warning: this format argument is not allowed in `#[diagnostic::on_unknown]` --> $DIR/incorrect_format_string.rs:8:42 | LL | #[diagnostic::on_unknown(message = "foo {A}")] - | ^ + | ^ remove this format argument | - = help: consider removing this format argument + = note: only `This` is allowed as a format argument, referring to the failed import -warning: format arguments are not allowed here +warning: positional arguments are not permitted in diagnostic attributes --> $DIR/incorrect_format_string.rs:13:40 | LL | #[diagnostic::on_unknown(label = "foo {}")] - | ^ + | ^ remove this format argument | - = help: consider removing this format argument + = help: you can print empty braces by escaping them -warning: format arguments are not allowed here +warning: this format argument is not allowed in `#[diagnostic::on_unknown]` --> $DIR/incorrect_format_string.rs:18:40 | LL | #[diagnostic::on_unknown(label = "foo {A}")] - | ^ + | ^ remove this format argument | - = help: consider removing this format argument + = note: only `This` is allowed as a format argument, referring to the failed import -warning: format arguments are not allowed here +warning: positional arguments are not permitted in diagnostic attributes --> $DIR/incorrect_format_string.rs:23:39 | LL | #[diagnostic::on_unknown(note = "foo {}")] - | ^ + | ^ remove this format argument | - = help: consider removing this format argument + = help: you can print empty braces by escaping them -warning: format arguments are not allowed here +warning: this format argument is not allowed in `#[diagnostic::on_unknown]` --> $DIR/incorrect_format_string.rs:28:39 | -LL | #[diagnostic::on_unknown(note = "foo {A}")] - | ^ +LL | #[diagnostic::on_unknown(note = "foo {Self} {ItemContext} {Trait} {A}")] + | ^^^^ remove this format argument + | + = note: only `This` is allowed as a format argument, referring to the failed import + +warning: this format argument is not allowed in `#[diagnostic::on_unknown]` + --> $DIR/incorrect_format_string.rs:28:46 + | +LL | #[diagnostic::on_unknown(note = "foo {Self} {ItemContext} {Trait} {A}")] + | ^^^^^^^^^^^ remove this format argument + | + = note: only `This` is allowed as a format argument, referring to the failed import + +warning: this format argument is not allowed in `#[diagnostic::on_unknown]` + --> $DIR/incorrect_format_string.rs:28:60 + | +LL | #[diagnostic::on_unknown(note = "foo {Self} {ItemContext} {Trait} {A}")] + | ^^^^^ remove this format argument + | + = note: only `This` is allowed as a format argument, referring to the failed import + +warning: this format argument is not allowed in `#[diagnostic::on_unknown]` + --> $DIR/incorrect_format_string.rs:28:68 + | +LL | #[diagnostic::on_unknown(note = "foo {Self} {ItemContext} {Trait} {A}")] + | ^ remove this format argument | - = help: consider removing this format argument + = note: only `This` is allowed as a format argument, referring to the failed import -error: aborting due to 6 previous errors; 6 warnings emitted +error: aborting due to 6 previous errors; 9 warnings emitted For more information about this error, try `rustc --explain E0432`. diff --git a/tests/ui/diagnostic_namespace/on_unknown/this_format_argument.rs b/tests/ui/diagnostic_namespace/on_unknown/this_format_argument.rs new file mode 100644 index 0000000000000..80ab7b973e8c0 --- /dev/null +++ b/tests/ui/diagnostic_namespace/on_unknown/this_format_argument.rs @@ -0,0 +1,45 @@ +#![feature(diagnostic_on_unknown)] +#![crate_type = "lib"] + +pub mod foo {} + +#[diagnostic::on_unknown(note = "the name of this item is a single ident: `{This}`")] +use foo::Foo; +//~^ERROR unresolved import `foo::Foo` +//~|NOTE the name of this item is a single ident: `Foo` +//~|NOTE no `Foo` in `foo` + +#[diagnostic::on_unknown(note = "the name of this item is a single ident: `{This}`")] +use foo::foo::Foo; +//~^ERROR unresolved import `foo::foo` +//~|NOTE the name of this item is a single ident: `foo` +//~|NOTE could not find `foo` in `foo` + +#[diagnostic::on_unknown(note = "the name of this item is two idents: `{This}`")] +use foo::{Bar, Foo}; +//~^ERROR unresolved imports `foo::Bar`, `foo::Foo` +//~|NOTE the name of this item is two idents: `Bar, Foo` +//~|NOTE no `Foo` in `foo` +//~|NOTE no `Bar` in `foo` + +#[diagnostic::on_unknown(note = "the name of this item is many idents: `{This}`")] +use foo::{ + Foo, + //~^ERROR unresolved imports `foo::Foo`, `foo::bar` + //~|NOTE the name of this item is many idents: `Foo, bar` + //~|NOTE no `Foo` in `foo` + bar::{Baz, Biz}, + //~^NOTE could not find `bar` in `foo` +}; + +#[diagnostic::on_unknown(note = "the name of this is: `{This}`")] +pub use doesnt_exist::*; +//~^ERROR unresolved import `doesnt_exist` +//~|NOTE use of unresolved module or unlinked crate `doesnt_exist` +//~|NOTE the name of this is: `doesnt_exist` + +#[diagnostic::on_unknown(note = "the name of this item is a single ident: `{This}`")] +use foo::Foo as DoNotUseForThisParam; +//~^ERROR unresolved import `foo::Foo` +//~|NOTE the name of this item is a single ident: `Foo` +//~|NOTE no `Foo` in `foo` diff --git a/tests/ui/diagnostic_namespace/on_unknown/this_format_argument.stderr b/tests/ui/diagnostic_namespace/on_unknown/this_format_argument.stderr new file mode 100644 index 0000000000000..aa6fd49d21c4e --- /dev/null +++ b/tests/ui/diagnostic_namespace/on_unknown/this_format_argument.stderr @@ -0,0 +1,60 @@ +error[E0432]: unresolved import `foo::Foo` + --> $DIR/this_format_argument.rs:7:5 + | +LL | use foo::Foo; + | ^^^^^^^^ no `Foo` in `foo` + | + = note: the name of this item is a single ident: `Foo` + +error[E0432]: unresolved import `foo::foo` + --> $DIR/this_format_argument.rs:13:10 + | +LL | use foo::foo::Foo; + | ^^^ could not find `foo` in `foo` + | + = note: the name of this item is a single ident: `foo` + +error[E0432]: unresolved imports `foo::Bar`, `foo::Foo` + --> $DIR/this_format_argument.rs:19:11 + | +LL | use foo::{Bar, Foo}; + | ^^^ ^^^ no `Foo` in `foo` + | | + | no `Bar` in `foo` + | + = note: the name of this item is two idents: `Bar, Foo` + +error[E0432]: unresolved imports `foo::Foo`, `foo::bar` + --> $DIR/this_format_argument.rs:27:5 + | +LL | Foo, + | ^^^ no `Foo` in `foo` +... +LL | bar::{Baz, Biz}, + | ^^^ could not find `bar` in `foo` + | + = note: the name of this item is many idents: `Foo, bar` + +error[E0432]: unresolved import `doesnt_exist` + --> $DIR/this_format_argument.rs:36:9 + | +LL | pub use doesnt_exist::*; + | ^^^^^^^^^^^^ use of unresolved module or unlinked crate `doesnt_exist` + | + = note: the name of this is: `doesnt_exist` +help: you might be missing a crate named `doesnt_exist`, add it to your project and import it in your code + | +LL + extern crate doesnt_exist; + | + +error[E0432]: unresolved import `foo::Foo` + --> $DIR/this_format_argument.rs:42:5 + | +LL | use foo::Foo as DoNotUseForThisParam; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ no `Foo` in `foo` + | + = note: the name of this item is a single ident: `Foo` + +error: aborting due to 6 previous errors + +For more information about this error, try `rustc --explain E0432`. diff --git a/tests/ui/diagnostic_namespace/on_unknown/unknown_import.rs b/tests/ui/diagnostic_namespace/on_unknown/unknown_import.rs index f2b0f059bb0a8..d09a87dcfea1a 100644 --- a/tests/ui/diagnostic_namespace/on_unknown/unknown_import.rs +++ b/tests/ui/diagnostic_namespace/on_unknown/unknown_import.rs @@ -7,7 +7,7 @@ pub mod foo { message = "first message", label = "first label", note = "custom note", - note = "custom note 2" + note = "custom note 2", )] use foo::Foo; //~^ERROR first message diff --git a/tests/ui/diagnostic_namespace/on_unmatch_args/report_warning_on_invalid_formats.rs b/tests/ui/diagnostic_namespace/on_unmatch_args/report_warning_on_invalid_formats.rs index 65cf18168638e..1fcaca8300f85 100644 --- a/tests/ui/diagnostic_namespace/on_unmatch_args/report_warning_on_invalid_formats.rs +++ b/tests/ui/diagnostic_namespace/on_unmatch_args/report_warning_on_invalid_formats.rs @@ -3,7 +3,10 @@ #[diagnostic::on_unmatch_args( message = "{T}! is missing arguments", - //~^ WARN unknown parameter `T` + //~^ WARN this format argument is not allowed in `#[diagnostic::on_unmatch_args]` + //~| NOTE only `This` is allowed as a format argument + //~| NOTE remove this format argument + //~| NOTE `#[warn(malformed_diagnostic_format_literals)]` (part of `#[warn(unknown_or_malformed_diagnostic_attributes)]`) on by default )] macro_rules! pair { ($ty:ty, $value:expr) => {}; diff --git a/tests/ui/diagnostic_namespace/on_unmatch_args/report_warning_on_invalid_formats.stderr b/tests/ui/diagnostic_namespace/on_unmatch_args/report_warning_on_invalid_formats.stderr index 2f631337c4416..fd68ad5570f31 100644 --- a/tests/ui/diagnostic_namespace/on_unmatch_args/report_warning_on_invalid_formats.stderr +++ b/tests/ui/diagnostic_namespace/on_unmatch_args/report_warning_on_invalid_formats.stderr @@ -1,10 +1,10 @@ -warning: unknown parameter `T` +warning: this format argument is not allowed in `#[diagnostic::on_unmatch_args]` --> $DIR/report_warning_on_invalid_formats.rs:5:17 | LL | message = "{T}! is missing arguments", - | ^ + | ^ remove this format argument | - = help: use `{This}` to refer to the macro name + = note: only `This` is allowed as a format argument, referring to the macro's name = note: `#[warn(malformed_diagnostic_format_literals)]` (part of `#[warn(unknown_or_malformed_diagnostic_attributes)]`) on by default warning: 1 warning emitted diff --git a/tests/ui/on-unimplemented/bad-annotation.rs b/tests/ui/on-unimplemented/bad-annotation.rs index 5350bf91de94a..7fec70df3a73c 100644 --- a/tests/ui/on-unimplemented/bad-annotation.rs +++ b/tests/ui/on-unimplemented/bad-annotation.rs @@ -23,7 +23,8 @@ trait NoContent {} trait ParameterNotPresent {} #[rustc_on_unimplemented(label = "Unimplemented error on `{Self}` with params `<{A},{B},{}>`")] -//~^ WARN positional format arguments are not allowed here +//~^ WARN positional arguments are not permitted in diagnostic attributes +//~| NOTE remove this format argument trait NoPositionalArgs {} #[rustc_on_unimplemented(lorem = "")] diff --git a/tests/ui/on-unimplemented/bad-annotation.stderr b/tests/ui/on-unimplemented/bad-annotation.stderr index 058014fd4e081..88666f359719b 100644 --- a/tests/ui/on-unimplemented/bad-annotation.stderr +++ b/tests/ui/on-unimplemented/bad-annotation.stderr @@ -1,59 +1,59 @@ error[E0232]: invalid flag in `on`-clause - --> $DIR/bad-annotation.rs:45:44 + --> $DIR/bad-annotation.rs:46:44 | LL | #[rustc_on_unimplemented(message = "x", on(desugared, message = "y"))] | ^^^^^^^^^ expected one of the `crate_local`, `direct` or `from_desugaring` flags, not `desugared` error[E0232]: empty `on`-clause in `#[rustc_on_unimplemented]` - --> $DIR/bad-annotation.rs:50:26 + --> $DIR/bad-annotation.rs:51:26 | LL | #[rustc_on_unimplemented(on(), message = "y")] | ^^^^ empty `on`-clause here error[E0232]: literals inside `on`-clauses are not supported - --> $DIR/bad-annotation.rs:70:29 + --> $DIR/bad-annotation.rs:71:29 | LL | #[rustc_on_unimplemented(on("y", message = "y"))] | ^^^ unexpected literal here error[E0232]: literals inside `on`-clauses are not supported - --> $DIR/bad-annotation.rs:75:29 + --> $DIR/bad-annotation.rs:76:29 | LL | #[rustc_on_unimplemented(on(42, message = "y"))] | ^^ unexpected literal here error[E0232]: expected a single predicate in `not(..)` - --> $DIR/bad-annotation.rs:80:32 + --> $DIR/bad-annotation.rs:81:32 | LL | #[rustc_on_unimplemented(on(not(a, b), message = "y"))] | ^^^^^^ unexpected quantity of predicates here error[E0232]: expected a single predicate in `not(..)` - --> $DIR/bad-annotation.rs:85:32 + --> $DIR/bad-annotation.rs:86:32 | LL | #[rustc_on_unimplemented(on(not(), message = "y"))] | ^^ unexpected quantity of predicates here error[E0232]: expected an identifier inside this `on`-clause - --> $DIR/bad-annotation.rs:90:29 + --> $DIR/bad-annotation.rs:91:29 | LL | #[rustc_on_unimplemented(on(thing::What, message = "y"))] | ^^^^^^^^^^^ expected an identifier here, not `thing::What` error[E0232]: expected an identifier inside this `on`-clause - --> $DIR/bad-annotation.rs:95:29 + --> $DIR/bad-annotation.rs:96:29 | LL | #[rustc_on_unimplemented(on(thing::What = "value", message = "y"))] | ^^^^^^^^^^^ expected an identifier here, not `thing::What` error[E0232]: this predicate is invalid - --> $DIR/bad-annotation.rs:100:29 + --> $DIR/bad-annotation.rs:101:29 | LL | #[rustc_on_unimplemented(on(aaaaaaaaaaaaaa(a, b), message = "y"))] | ^^^^^^^^^^^^^^ expected one of `any`, `all` or `not` here, not `aaaaaaaaaaaaaa` error[E0232]: invalid flag in `on`-clause - --> $DIR/bad-annotation.rs:105:29 + --> $DIR/bad-annotation.rs:106:29 | LL | #[rustc_on_unimplemented(on(something, message = "y"))] | ^^^^^^^^^ expected one of the `crate_local`, `direct` or `from_desugaring` flags, not `something` @@ -67,13 +67,13 @@ LL | #[rustc_on_unimplemented(label = "Unimplemented error on `{Self}` with para = note: `#[warn(malformed_diagnostic_format_literals)]` (part of `#[warn(unknown_or_malformed_diagnostic_attributes)]`) on by default warning: there is no parameter `_Self` on trait `InvalidName` - --> $DIR/bad-annotation.rs:110:29 + --> $DIR/bad-annotation.rs:111:29 | LL | #[rustc_on_unimplemented(on(_Self = "y", message = "y"))] | ^^^^^^^^^^^ warning: there is no parameter `abc` on trait `InvalidName2` - --> $DIR/bad-annotation.rs:114:29 + --> $DIR/bad-annotation.rs:115:29 | LL | #[rustc_on_unimplemented(on(abc = "y", message = "y"))] | ^^^^^^^^^ @@ -87,16 +87,16 @@ LL | #[rustc_on_unimplemented] = help: see = note: `#[warn(malformed_diagnostic_attributes)]` (part of `#[warn(unknown_or_malformed_diagnostic_attributes)]`) on by default -warning: positional format arguments are not allowed here +warning: positional arguments are not permitted in diagnostic attributes --> $DIR/bad-annotation.rs:25:90 | LL | #[rustc_on_unimplemented(label = "Unimplemented error on `{Self}` with params `<{A},{B},{}>`")] - | ^ + | ^ remove this format argument | - = help: only named format arguments with the name of one of the generic types are allowed in this context + = help: you can print empty braces by escaping them warning: malformed `rustc_on_unimplemented` attribute - --> $DIR/bad-annotation.rs:29:26 + --> $DIR/bad-annotation.rs:30:26 | LL | #[rustc_on_unimplemented(lorem = "")] | ^^^^^^^^^^ invalid option found here @@ -104,7 +104,7 @@ LL | #[rustc_on_unimplemented(lorem = "")] = help: see warning: malformed `rustc_on_unimplemented` attribute - --> $DIR/bad-annotation.rs:34:26 + --> $DIR/bad-annotation.rs:35:26 | LL | #[rustc_on_unimplemented(lorem(ipsum(dolor)))] | ^^^^^^^^^^^^^^^^^^^ invalid option found here @@ -112,7 +112,7 @@ LL | #[rustc_on_unimplemented(lorem(ipsum(dolor)))] = help: see warning: `message` is ignored due to previous definition of `message` - --> $DIR/bad-annotation.rs:39:41 + --> $DIR/bad-annotation.rs:40:41 | LL | #[rustc_on_unimplemented(message = "x", message = "y")] | ------------- ^^^^^^^^^^^^^ `message` is later redundantly declared here @@ -120,7 +120,7 @@ LL | #[rustc_on_unimplemented(message = "x", message = "y")] | `message` is first declared here warning: malformed `rustc_on_unimplemented` attribute - --> $DIR/bad-annotation.rs:55:26 + --> $DIR/bad-annotation.rs:56:26 | LL | #[rustc_on_unimplemented(on = "x", message = "y")] | ^^^^^^^^ invalid option found here @@ -128,7 +128,7 @@ LL | #[rustc_on_unimplemented(on = "x", message = "y")] = help: see warning: malformed `rustc_on_unimplemented` attribute - --> $DIR/bad-annotation.rs:60:26 + --> $DIR/bad-annotation.rs:61:26 | LL | #[rustc_on_unimplemented(on(Self = "y"), message = "y")] | ^^^^^^^^^^^^^^ invalid option found here @@ -136,7 +136,7 @@ LL | #[rustc_on_unimplemented(on(Self = "y"), message = "y")] = help: see warning: malformed `rustc_on_unimplemented` attribute - --> $DIR/bad-annotation.rs:65:46 + --> $DIR/bad-annotation.rs:66:46 | LL | #[rustc_on_unimplemented(on(from_desugaring, on(from_desugaring, message = "x")), message = "y")] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ invalid option found here From 2b46d9204a82c50d57b66ba31b8dbbc5bcbd56bc Mon Sep 17 00:00:00 2001 From: Qai Juang <237468078+qaijuang@users.noreply.github.com> Date: Wed, 22 Apr 2026 08:17:17 -0400 Subject: [PATCH 172/183] Improve suggestion for `$`-prefixed fragment specifiers --- compiler/rustc_expand/src/mbe/quoted.rs | 46 +++++++++++++++---- tests/ui/macros/macro-missing-fragment.rs | 4 ++ tests/ui/macros/macro-missing-fragment.stderr | 16 ++++++- 3 files changed, 56 insertions(+), 10 deletions(-) diff --git a/compiler/rustc_expand/src/mbe/quoted.rs b/compiler/rustc_expand/src/mbe/quoted.rs index a698db5437598..92d19820848b4 100644 --- a/compiler/rustc_expand/src/mbe/quoted.rs +++ b/compiler/rustc_expand/src/mbe/quoted.rs @@ -2,6 +2,7 @@ use rustc_ast::token::{self, Delimiter, IdentIsRaw, NonterminalKind, Token}; use rustc_ast::tokenstream::TokenStreamIter; use rustc_ast::{NodeId, tokenstream}; use rustc_ast_pretty::pprust; +use rustc_errors::Applicability; use rustc_feature::Features; use rustc_session::Session; use rustc_session::parse::feature_err; @@ -88,16 +89,17 @@ fn parse( continue; }; - // Push a metavariable with no fragment specifier at the given span - let mut missing_fragment_specifier = |span| { + let fallback_metavar_decl = + |span| TokenTree::MetaVarDecl { span, name: ident, kind: NonterminalKind::TT }; + // Emit a missing-fragment diagnostic and return a `TokenTree` fallback so parsing can + // continue. + let missing_fragment_specifier = |span, add_span| { sess.dcx().emit_err(errors::MissingFragmentSpecifier { span, - add_span: span.shrink_to_hi(), + add_span, valid: VALID_FRAGMENT_NAMES_MSG, }); - - // Fall back to a `TokenTree` since that will match anything if we continue expanding. - result.push(TokenTree::MetaVarDecl { span, name: ident, kind: NonterminalKind::TT }); + fallback_metavar_decl(span) }; // Not consuming the next token immediately, as it may not be a colon @@ -112,13 +114,39 @@ fn parse( // since if it's not a token then it will be an invalid declaration. let Some(tokenstream::TokenTree::Token(token, _)) = iter.next() else { // Invalid, return a nice source location as `var:` - missing_fragment_specifier(colon_span.with_lo(start_sp.lo())); + result.push(missing_fragment_specifier( + colon_span.with_lo(start_sp.lo()), + colon_span.shrink_to_hi(), + )); continue; }; let Some((fragment, _)) = token.ident() else { // No identifier for the fragment specifier; - missing_fragment_specifier(token.span); + if token.kind == token::Dollar + && iter.peek().is_some_and(|next| { + matches!( + next, + tokenstream::TokenTree::Token(next_token, _) + if next_token.ident().is_some() + ) + }) + { + let mut err = + sess.dcx().struct_span_err(token.span, "missing fragment specifier"); + err.note("fragment specifiers must be provided"); + err.help(VALID_FRAGMENT_NAMES_MSG); + err.span_suggestion_verbose( + token.span, + "fragment specifiers should not be prefixed with `$`", + "", + Applicability::MaybeIncorrect, + ); + err.emit(); + result.push(fallback_metavar_decl(token.span)); + } else { + result.push(missing_fragment_specifier(token.span, token.span.shrink_to_hi())); + } continue; }; @@ -146,7 +174,7 @@ fn parse( } else { // Whether it's none or some other tree, it doesn't belong to // the current meta variable, returning the original span. - missing_fragment_specifier(start_sp); + result.push(missing_fragment_specifier(start_sp, start_sp.shrink_to_hi())); } } result diff --git a/tests/ui/macros/macro-missing-fragment.rs b/tests/ui/macros/macro-missing-fragment.rs index 7ed9074020e4b..827c7fc319272 100644 --- a/tests/ui/macros/macro-missing-fragment.rs +++ b/tests/ui/macros/macro-missing-fragment.rs @@ -13,6 +13,10 @@ macro_rules! unused_macro { ( $name ) => {}; //~ ERROR missing fragment } +macro_rules! accidental_dollar_prefix { + ( $test:$tt ) => {}; //~ ERROR missing fragment +} + fn main() { used_arm!(); used_macro_unused_arm!(); diff --git a/tests/ui/macros/macro-missing-fragment.stderr b/tests/ui/macros/macro-missing-fragment.stderr index 886292378d1a0..b1b9bf3d8aa97 100644 --- a/tests/ui/macros/macro-missing-fragment.stderr +++ b/tests/ui/macros/macro-missing-fragment.stderr @@ -37,5 +37,19 @@ help: try adding a specifier here LL | ( $name:spec ) => {}; | +++++ -error: aborting due to 3 previous errors +error: missing fragment specifier + --> $DIR/macro-missing-fragment.rs:17:13 + | +LL | ( $test:$tt ) => {}; + | ^ + | + = note: fragment specifiers must be provided + = help: valid fragment specifiers are `ident`, `block`, `stmt`, `expr`, `pat`, `ty`, `lifetime`, `literal`, `path`, `meta`, `tt`, `item` and `vis`, along with `expr_2021` and `pat_param` for edition compatibility +help: fragment specifiers should not be prefixed with `$` + | +LL - ( $test:$tt ) => {}; +LL + ( $test:tt ) => {}; + | + +error: aborting due to 4 previous errors From 3851c60cf821639df9355d62fc7030b6aa0a64eb Mon Sep 17 00:00:00 2001 From: Folkert de Vries Date: Fri, 24 Apr 2026 22:18:22 +0200 Subject: [PATCH 173/183] make the `core::ffi::va_list` module private the types are exported from `core::ffi` itself --- library/core/src/ffi/mod.rs | 8 +------- library/core/src/ffi/va_list.rs | 6 ++++++ library/core/src/intrinsics/mod.rs | 2 +- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/library/core/src/ffi/mod.rs b/library/core/src/ffi/mod.rs index f1b928da7ef3c..3f1aa54050a31 100644 --- a/library/core/src/ffi/mod.rs +++ b/library/core/src/ffi/mod.rs @@ -23,6 +23,7 @@ use crate::fmt; #[stable(feature = "c_str_module", since = "1.88.0")] pub mod c_str; +mod va_list; #[unstable( feature = "c_variadic", issue = "44930", @@ -30,13 +31,6 @@ pub mod c_str; )] pub use self::va_list::{VaArgSafe, VaList}; -#[unstable( - feature = "c_variadic", - issue = "44930", - reason = "the `c_variadic` feature has not been properly tested on all supported platforms" -)] -pub mod va_list; - mod primitives; #[stable(feature = "core_ffi_c", since = "1.64.0")] pub use self::primitives::{ diff --git a/library/core/src/ffi/va_list.rs b/library/core/src/ffi/va_list.rs index 020ea4513078d..0a35dc32ef19c 100644 --- a/library/core/src/ffi/va_list.rs +++ b/library/core/src/ffi/va_list.rs @@ -2,6 +2,12 @@ //! //! Better known as "varargs". +#![unstable( + feature = "c_variadic", + issue = "44930", + reason = "the `c_variadic` feature has not been properly tested on all supported platforms" +)] + #[cfg(not(target_arch = "xtensa"))] use crate::ffi::c_void; use crate::fmt; diff --git a/library/core/src/intrinsics/mod.rs b/library/core/src/intrinsics/mod.rs index 94d0c7eab9227..c71085ef9f97d 100644 --- a/library/core/src/intrinsics/mod.rs +++ b/library/core/src/intrinsics/mod.rs @@ -53,7 +53,7 @@ issue = "none" )] -use crate::ffi::va_list::{VaArgSafe, VaList}; +use crate::ffi::{VaArgSafe, VaList}; use crate::marker::{ConstParamTy, DiscriminantKind, PointeeSized, Tuple}; use crate::{mem, ptr}; From d439d07af224ce3e1ae837972f580ce0afd60f0e Mon Sep 17 00:00:00 2001 From: Weihang Lo Date: Fri, 24 Apr 2026 17:43:12 -0400 Subject: [PATCH 174/183] Update cargo submodule --- src/llvm-project | 2 +- src/tools/cargo | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/llvm-project b/src/llvm-project index eaab4d9841b9a..1cb4e3833c191 160000 --- a/src/llvm-project +++ b/src/llvm-project @@ -1 +1 @@ -Subproject commit eaab4d9841b9a8a12783d927b2df2291c1c79269 +Subproject commit 1cb4e3833c1919c2e6fb579a23ac0e2b22587b7e diff --git a/src/tools/cargo b/src/tools/cargo index 06ac0e7c05770..eb9b60f1f6604 160000 --- a/src/tools/cargo +++ b/src/tools/cargo @@ -1 +1 @@ -Subproject commit 06ac0e7c05770a8c7bbf67bdd12fa1a1eefdc8ae +Subproject commit eb9b60f1f6604b5e022c56be31692c215b8ba11d From d5b941d163616f12bda3595434414aa3bc7f5d15 Mon Sep 17 00:00:00 2001 From: Apersoma <95072312+Apersoma@users.noreply.github.com> Date: Fri, 24 Apr 2026 23:06:04 +0000 Subject: [PATCH 175/183] added float masks feature --- library/core/src/num/f128.rs | 82 +++++++++++++++++++++++++---- library/core/src/num/f16.rs | 84 ++++++++++++++++++++++++++---- library/core/src/num/f32.rs | 73 ++++++++++++++++++++++---- library/core/src/num/f64.rs | 73 ++++++++++++++++++++++---- library/core/src/num/imp/traits.rs | 12 ++--- 5 files changed, 282 insertions(+), 42 deletions(-) diff --git a/library/core/src/num/f128.rs b/library/core/src/num/f128.rs index 68c87b48de94d..24ed84dcb0dc3 100644 --- a/library/core/src/num/f128.rs +++ b/library/core/src/num/f128.rs @@ -339,14 +339,78 @@ impl f128 { #[unstable(feature = "float_exact_integer_constants", issue = "152466")] pub const MIN_EXACT_INTEGER: i128 = -Self::MAX_EXACT_INTEGER; - /// Sign bit - pub(crate) const SIGN_MASK: u128 = 0x8000_0000_0000_0000_0000_0000_0000_0000; + /// The mask of the bit used to encode the sign of an [`f128`]. + /// + /// This bit is set when the sign is negative and unset when the sign is + /// positive. + /// If you only need to check whether a value is positive or negative, + /// [`is_sign_positive`] or [`is_sign_negative`] can be used. + /// + /// [`is_sign_positive`]: f128::is_sign_positive + /// [`is_sign_negative`]: f128::is_sign_negative + /// ```rust + /// #![feature(float_masks)] + /// #![feature(f128)] + /// # #[cfg(target_has_reliable_f128)] { + /// let sign_mask = f128::SIGN_MASK; + /// let a = 1.6552f128; + /// let a_bits = a.to_bits(); + /// + /// assert_eq!(a_bits & sign_mask, 0x0); + /// assert_eq!(f128::from_bits(a_bits ^ sign_mask), -a); + /// assert_eq!(sign_mask, (-0.0f128).to_bits()); + /// # } + /// ``` + #[unstable(feature = "float_masks", issue = "154064")] + pub const SIGN_MASK: u128 = 0x8000_0000_0000_0000_0000_0000_0000_0000; - /// Exponent mask - pub(crate) const EXP_MASK: u128 = 0x7fff_0000_0000_0000_0000_0000_0000_0000; + /// The mask of the bits used to encode the exponent of an [`f128`]. + /// + /// Note that the exponent is stored as a biased value, with a bias of 16383 for `f128`. + /// + /// ```rust + /// #![feature(float_masks)] + /// #![feature(f128)] + /// # #[cfg(target_has_reliable_f128)] { + /// fn get_exp(a: f128) -> i128 { + /// let bias = 16383; + /// let biased = a.to_bits() & f128::EXPONENT_MASK; + /// (biased >> (f128::MANTISSA_DIGITS - 1)).cast_signed() - bias + /// } + /// + /// assert_eq!(get_exp(0.5), -1); + /// assert_eq!(get_exp(1.0), 0); + /// assert_eq!(get_exp(2.0), 1); + /// assert_eq!(get_exp(4.0), 2); + /// # } + /// ``` + #[unstable(feature = "float_masks", issue = "154064")] + pub const EXPONENT_MASK: u128 = 0x7fff_0000_0000_0000_0000_0000_0000_0000; - /// Mantissa mask - pub(crate) const MAN_MASK: u128 = 0x0000_ffff_ffff_ffff_ffff_ffff_ffff_ffff; + /// The mask of the bits used to encode the mantissa of an [`f128`]. + /// + /// ```rust + /// #![feature(float_masks)] + /// #![feature(f128)] + /// # #[cfg(target_has_reliable_f128)] { + /// let mantissa_mask = f128::MANTISSA_MASK; + /// + /// assert_eq!(0f128.to_bits() & mantissa_mask, 0x0); + /// assert_eq!(1f128.to_bits() & mantissa_mask, 0x0); + /// + /// // multiplying a finite value by a power of 2 doesn't change its mantissa + /// // unless the result or initial value is not normal. + /// let a = 1.6552f128; + /// let b = 4.0 * a; + /// assert_eq!(a.to_bits() & mantissa_mask, b.to_bits() & mantissa_mask); + /// + /// // The maximum and minimum values have a saturated significand + /// assert_eq!(f128::MAX.to_bits() & f128::MANTISSA_MASK, f128::MANTISSA_MASK); + /// assert_eq!(f128::MIN.to_bits() & f128::MANTISSA_MASK, f128::MANTISSA_MASK); + /// # } + /// ``` + #[unstable(feature = "float_masks", issue = "154064")] + pub const MANTISSA_MASK: u128 = 0x0000_ffff_ffff_ffff_ffff_ffff_ffff_ffff; /// Minimum representable positive value (min subnormal) const TINY_BITS: u128 = 0x1; @@ -510,9 +574,9 @@ impl f128 { #[unstable(feature = "f128", issue = "116909")] pub const fn classify(self) -> FpCategory { let bits = self.to_bits(); - match (bits & Self::MAN_MASK, bits & Self::EXP_MASK) { - (0, Self::EXP_MASK) => FpCategory::Infinite, - (_, Self::EXP_MASK) => FpCategory::Nan, + match (bits & Self::MANTISSA_MASK, bits & Self::EXPONENT_MASK) { + (0, Self::EXPONENT_MASK) => FpCategory::Infinite, + (_, Self::EXPONENT_MASK) => FpCategory::Nan, (0, 0) => FpCategory::Zero, (_, 0) => FpCategory::Subnormal, _ => FpCategory::Normal, diff --git a/library/core/src/num/f16.rs b/library/core/src/num/f16.rs index 3412e49c49cd0..d0cc9580765c0 100644 --- a/library/core/src/num/f16.rs +++ b/library/core/src/num/f16.rs @@ -333,14 +333,80 @@ impl f16 { #[unstable(feature = "float_exact_integer_constants", issue = "152466")] pub const MIN_EXACT_INTEGER: i16 = -Self::MAX_EXACT_INTEGER; - /// Sign bit - pub(crate) const SIGN_MASK: u16 = 0x8000; + /// The mask of the bit used to encode the sign of an [`f16`]. + /// + /// This bit is set when the sign is negative and unset when the sign is + /// positive. + /// If you only need to check whether a value is positive or negative, + /// [`is_sign_positive`] or [`is_sign_negative`] can be used. + /// + /// [`is_sign_positive`]: f16::is_sign_positive + /// [`is_sign_negative`]: f16::is_sign_negative + /// ```rust + /// #![feature(float_masks)] + /// #![feature(f16)] + /// # #[cfg(target_has_reliable_f16)] { + /// let sign_mask = f16::SIGN_MASK; + /// let a = 1.6552f16; + /// let a_bits = a.to_bits(); + /// + /// assert_eq!(a_bits & sign_mask, 0x0); + /// assert_eq!(f16::from_bits(a_bits ^ sign_mask), -a); + /// assert_eq!(sign_mask, (-0.0f16).to_bits()); + /// # } + /// ``` + #[unstable(feature = "float_masks", issue = "154064")] + pub const SIGN_MASK: u16 = 0x8000; - /// Exponent mask - pub(crate) const EXP_MASK: u16 = 0x7c00; + /// The mask of the bits used to encode the exponent of an [`f16`]. + /// + /// Note that the exponent is stored as a biased value, with a bias of 15 for `f16`. + /// + /// ```rust + /// #![feature(float_masks)] + /// #![feature(f16)] + /// # #[cfg(target_has_reliable_f16)] { + /// let exponent_mask = f16::EXPONENT_MASK; + /// + /// fn get_exp(a: f16) -> i16 { + /// let bias = 15; + /// let biased = a.to_bits() & f16::EXPONENT_MASK; + /// (biased >> (f16::MANTISSA_DIGITS - 1)).cast_signed() - bias + /// } + /// + /// assert_eq!(get_exp(0.5), -1); + /// assert_eq!(get_exp(1.0), 0); + /// assert_eq!(get_exp(2.0), 1); + /// assert_eq!(get_exp(4.0), 2); + /// # } + /// ``` + #[unstable(feature = "float_masks", issue = "154064")] + pub const EXPONENT_MASK: u16 = 0x7c00; - /// Mantissa mask - pub(crate) const MAN_MASK: u16 = 0x03ff; + /// The mask of the bits used to encode the mantissa of an [`f16`]. + /// + /// ```rust + /// #![feature(float_masks)] + /// #![feature(f16)] + /// # #[cfg(target_has_reliable_f16)] { + /// let mantissa_mask = f16::MANTISSA_MASK; + /// + /// assert_eq!(0f16.to_bits() & mantissa_mask, 0x0); + /// assert_eq!(1f16.to_bits() & mantissa_mask, 0x0); + /// + /// // multiplying a finite value by a power of 2 doesn't change its mantissa + /// // unless the result or initial value is not normal. + /// let a = 1.6552f16; + /// let b = 4.0 * a; + /// assert_eq!(a.to_bits() & mantissa_mask, b.to_bits() & mantissa_mask); + /// + /// // The maximum and minimum values have a saturated significand + /// assert_eq!(f16::MAX.to_bits() & f16::MANTISSA_MASK, f16::MANTISSA_MASK); + /// assert_eq!(f16::MIN.to_bits() & f16::MANTISSA_MASK, f16::MANTISSA_MASK); + /// # } + /// ``` + #[unstable(feature = "float_masks", issue = "154064")] + pub const MANTISSA_MASK: u16 = 0x03ff; /// Minimum representable positive value (min subnormal) const TINY_BITS: u16 = 0x1; @@ -502,9 +568,9 @@ impl f16 { #[unstable(feature = "f16", issue = "116909")] pub const fn classify(self) -> FpCategory { let b = self.to_bits(); - match (b & Self::MAN_MASK, b & Self::EXP_MASK) { - (0, Self::EXP_MASK) => FpCategory::Infinite, - (_, Self::EXP_MASK) => FpCategory::Nan, + match (b & Self::MANTISSA_MASK, b & Self::EXPONENT_MASK) { + (0, Self::EXPONENT_MASK) => FpCategory::Infinite, + (_, Self::EXPONENT_MASK) => FpCategory::Nan, (0, 0) => FpCategory::Zero, (_, 0) => FpCategory::Subnormal, _ => FpCategory::Normal, diff --git a/library/core/src/num/f32.rs b/library/core/src/num/f32.rs index e33cb098e4e8d..0a80e19f51a5e 100644 --- a/library/core/src/num/f32.rs +++ b/library/core/src/num/f32.rs @@ -572,14 +572,69 @@ impl f32 { #[unstable(feature = "float_exact_integer_constants", issue = "152466")] pub const MIN_EXACT_INTEGER: i32 = -Self::MAX_EXACT_INTEGER; - /// Sign bit - pub(crate) const SIGN_MASK: u32 = 0x8000_0000; + /// The mask of the bit used to encode the sign of an [`f32`]. + /// + /// This bit is set when the sign is negative and unset when the sign is + /// positive. + /// If you only need to check whether a value is positive or negative, + /// [`is_sign_positive`] or [`is_sign_negative`] can be used. + /// + /// [`is_sign_positive`]: f32::is_sign_positive + /// [`is_sign_negative`]: f32::is_sign_negative + /// ```rust + /// #![feature(float_masks)] + /// let sign_mask = f32::SIGN_MASK; + /// let a = 1.6552f32; + /// let a_bits = a.to_bits(); + /// + /// assert_eq!(a_bits & sign_mask, 0x0); + /// assert_eq!(f32::from_bits(a_bits ^ sign_mask), -a); + /// assert_eq!(sign_mask, (-0.0f32).to_bits()); + /// ``` + #[unstable(feature = "float_masks", issue = "154064")] + pub const SIGN_MASK: u32 = 0x8000_0000; - /// Exponent mask - pub(crate) const EXP_MASK: u32 = 0x7f80_0000; + /// The mask of the bits used to encode the exponent of an [`f32`]. + /// + /// Note that the exponent is stored as a biased value, with a bias of 127 for `f32`. + /// + /// ```rust + /// #![feature(float_masks)] + /// fn get_exp(a: f32) -> i32 { + /// let bias = 127; + /// let biased = a.to_bits() & f32::EXPONENT_MASK; + /// (biased >> (f32::MANTISSA_DIGITS - 1)).cast_signed() - bias + /// } + /// + /// assert_eq!(get_exp(0.5), -1); + /// assert_eq!(get_exp(1.0), 0); + /// assert_eq!(get_exp(2.0), 1); + /// assert_eq!(get_exp(4.0), 2); + /// ``` + #[unstable(feature = "float_masks", issue = "154064")] + pub const EXPONENT_MASK: u32 = 0x7f80_0000; - /// Mantissa mask - pub(crate) const MAN_MASK: u32 = 0x007f_ffff; + /// The mask of the bits used to encode the mantissa of an [`f32`]. + /// + /// ```rust + /// #![feature(float_masks)] + /// let mantissa_mask = f32::MANTISSA_MASK; + /// + /// assert_eq!(0f32.to_bits() & mantissa_mask, 0x0); + /// assert_eq!(1f32.to_bits() & mantissa_mask, 0x0); + /// + /// // multiplying a finite value by a power of 2 doesn't change its mantissa + /// // unless the result or initial value is not normal. + /// let a = 1.6552f32; + /// let b = 4.0 * a; + /// assert_eq!(a.to_bits() & mantissa_mask, b.to_bits() & mantissa_mask); + /// + /// // The maximum and minimum values have a saturated significand + /// assert_eq!(f32::MAX.to_bits() & f32::MANTISSA_MASK, f32::MANTISSA_MASK); + /// assert_eq!(f32::MIN.to_bits() & f32::MANTISSA_MASK, f32::MANTISSA_MASK); + /// ``` + #[unstable(feature = "float_masks", issue = "154064")] + pub const MANTISSA_MASK: u32 = 0x007f_ffff; /// Minimum representable positive value (min subnormal) const TINY_BITS: u32 = 0x1; @@ -730,9 +785,9 @@ impl f32 { // of our tests is able to find any difference between the complicated and the naive // version, so now we are back to the naive version. let b = self.to_bits(); - match (b & Self::MAN_MASK, b & Self::EXP_MASK) { - (0, Self::EXP_MASK) => FpCategory::Infinite, - (_, Self::EXP_MASK) => FpCategory::Nan, + match (b & Self::MANTISSA_MASK, b & Self::EXPONENT_MASK) { + (0, Self::EXPONENT_MASK) => FpCategory::Infinite, + (_, Self::EXPONENT_MASK) => FpCategory::Nan, (0, 0) => FpCategory::Zero, (_, 0) => FpCategory::Subnormal, _ => FpCategory::Normal, diff --git a/library/core/src/num/f64.rs b/library/core/src/num/f64.rs index 872f567efafdc..4d57f1dab8524 100644 --- a/library/core/src/num/f64.rs +++ b/library/core/src/num/f64.rs @@ -571,14 +571,69 @@ impl f64 { #[unstable(feature = "float_exact_integer_constants", issue = "152466")] pub const MIN_EXACT_INTEGER: i64 = -Self::MAX_EXACT_INTEGER; - /// Sign bit - pub(crate) const SIGN_MASK: u64 = 0x8000_0000_0000_0000; + /// The mask of the bit used to encode the sign of an [`f64`]. + /// + /// This bit is set when the sign is negative and unset when the sign is + /// positive. + /// If you only need to check whether a value is positive or negative, + /// [`is_sign_positive`] or [`is_sign_negative`] can be used. + /// + /// [`is_sign_positive`]: f64::is_sign_positive + /// [`is_sign_negative`]: f64::is_sign_negative + /// ```rust + /// #![feature(float_masks)] + /// let sign_mask = f64::SIGN_MASK; + /// let a = 1.6552f64; + /// let a_bits = a.to_bits(); + /// + /// assert_eq!(a_bits & sign_mask, 0x0); + /// assert_eq!(f64::from_bits(a_bits ^ sign_mask), -a); + /// assert_eq!(sign_mask, (-0.0f64).to_bits()); + /// ``` + #[unstable(feature = "float_masks", issue = "154064")] + pub const SIGN_MASK: u64 = 0x8000_0000_0000_0000; - /// Exponent mask - pub(crate) const EXP_MASK: u64 = 0x7ff0_0000_0000_0000; + /// The mask of the bits used to encode the exponent of an [`f64`]. + /// + /// Note that the exponent is stored as a biased value, with a bias of 1024 for `f64`. + /// + /// ```rust + /// #![feature(float_masks)] + /// fn get_exp(a: f64) -> i64 { + /// let bias = 1023; + /// let biased = a.to_bits() & f64::EXPONENT_MASK; + /// (biased >> (f64::MANTISSA_DIGITS - 1)).cast_signed() - bias + /// } + /// + /// assert_eq!(get_exp(0.5), -1); + /// assert_eq!(get_exp(1.0), 0); + /// assert_eq!(get_exp(2.0), 1); + /// assert_eq!(get_exp(4.0), 2); + /// ``` + #[unstable(feature = "float_masks", issue = "154064")] + pub const EXPONENT_MASK: u64 = 0x7ff0_0000_0000_0000; - /// Mantissa mask - pub(crate) const MAN_MASK: u64 = 0x000f_ffff_ffff_ffff; + /// The mask of the bits used to encode the mantissa of an [`f64`]. + /// + /// ```rust + /// #![feature(float_masks)] + /// let mantissa_mask = f64::MANTISSA_MASK; + /// + /// assert_eq!(0f64.to_bits() & mantissa_mask, 0x0); + /// assert_eq!(1f64.to_bits() & mantissa_mask, 0x0); + /// + /// // multiplying a finite value by a power of 2 doesn't change its mantissa + /// // unless the result or initial value is not normal. + /// let a = 1.6552f64; + /// let b = 4.0 * a; + /// assert_eq!(a.to_bits() & mantissa_mask, b.to_bits() & mantissa_mask); + /// + /// // The maximum and minimum values have a saturated significand + /// assert_eq!(f64::MAX.to_bits() & f64::MANTISSA_MASK, f64::MANTISSA_MASK); + /// assert_eq!(f64::MIN.to_bits() & f64::MANTISSA_MASK, f64::MANTISSA_MASK); + /// ``` + #[unstable(feature = "float_masks", issue = "154064")] + pub const MANTISSA_MASK: u64 = 0x000f_ffff_ffff_ffff; /// Minimum representable positive value (min subnormal) const TINY_BITS: u64 = 0x1; @@ -729,9 +784,9 @@ impl f64 { // of our tests is able to find any difference between the complicated and the naive // version, so now we are back to the naive version. let b = self.to_bits(); - match (b & Self::MAN_MASK, b & Self::EXP_MASK) { - (0, Self::EXP_MASK) => FpCategory::Infinite, - (_, Self::EXP_MASK) => FpCategory::Nan, + match (b & Self::MANTISSA_MASK, b & Self::EXPONENT_MASK) { + (0, Self::EXPONENT_MASK) => FpCategory::Infinite, + (_, Self::EXPONENT_MASK) => FpCategory::Nan, (0, 0) => FpCategory::Zero, (_, 0) => FpCategory::Subnormal, _ => FpCategory::Normal, diff --git a/library/core/src/num/imp/traits.rs b/library/core/src/num/imp/traits.rs index 7b84f7a4a5aa2..3a7ea23f73f31 100644 --- a/library/core/src/num/imp/traits.rs +++ b/library/core/src/num/imp/traits.rs @@ -204,8 +204,8 @@ impl Float for f16 { const BITS: u32 = 16; const SIG_TOTAL_BITS: u32 = Self::MANTISSA_DIGITS; - const EXP_MASK: Self::Int = Self::EXP_MASK; - const SIG_MASK: Self::Int = Self::MAN_MASK; + const EXP_MASK: Self::Int = Self::EXPONENT_MASK; + const SIG_MASK: Self::Int = Self::MANTISSA_MASK; const MIN_EXPONENT_ROUND_TO_EVEN: i32 = -22; const MAX_EXPONENT_ROUND_TO_EVEN: i32 = 5; @@ -238,8 +238,8 @@ impl Float for f32 { const BITS: u32 = 32; const SIG_TOTAL_BITS: u32 = Self::MANTISSA_DIGITS; - const EXP_MASK: Self::Int = Self::EXP_MASK; - const SIG_MASK: Self::Int = Self::MAN_MASK; + const EXP_MASK: Self::Int = Self::EXPONENT_MASK; + const SIG_MASK: Self::Int = Self::MANTISSA_MASK; const MIN_EXPONENT_ROUND_TO_EVEN: i32 = -17; const MAX_EXPONENT_ROUND_TO_EVEN: i32 = 10; @@ -271,8 +271,8 @@ impl Float for f64 { const BITS: u32 = 64; const SIG_TOTAL_BITS: u32 = Self::MANTISSA_DIGITS; - const EXP_MASK: Self::Int = Self::EXP_MASK; - const SIG_MASK: Self::Int = Self::MAN_MASK; + const EXP_MASK: Self::Int = Self::EXPONENT_MASK; + const SIG_MASK: Self::Int = Self::MANTISSA_MASK; const MIN_EXPONENT_ROUND_TO_EVEN: i32 = -4; const MAX_EXPONENT_ROUND_TO_EVEN: i32 = 23; From 61ff157bd47ce626795f1672d6cc7bf3ba292fd6 Mon Sep 17 00:00:00 2001 From: yuk1ty Date: Sat, 11 Apr 2026 21:28:03 +0900 Subject: [PATCH 176/183] Address custom type implementing Derefs to suggest UFCS clone --- .../src/diagnostics/conflict_errors.rs | 4 +- .../rustc_borrowck/src/diagnostics/mod.rs | 22 ++-- .../src/diagnostics/move_errors.rs | 101 +++++++++++++++--- .../ufcs-for-deref-inner-clone.fixed | 16 +++ .../suggestions/ufcs-for-deref-inner-clone.rs | 16 +++ .../ufcs-for-deref-inner-clone.stderr | 14 +++ 6 files changed, 146 insertions(+), 27 deletions(-) create mode 100644 tests/ui/suggestions/ufcs-for-deref-inner-clone.fixed create mode 100644 tests/ui/suggestions/ufcs-for-deref-inner-clone.rs create mode 100644 tests/ui/suggestions/ufcs-for-deref-inner-clone.stderr diff --git a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs index 639cb75fdd28b..2735c800c4a38 100644 --- a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs @@ -254,9 +254,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> { maybe_reinitialized_locations_is_empty: maybe_reinitialized_locations .is_empty(), }; - // The return value indicates whether a clone suggestion was emitted; - // redundancy is already handled via the `FnSelfUse` check below. - let _ = self.explain_captures( + self.explain_captures( &mut err, span, move_span, diff --git a/compiler/rustc_borrowck/src/diagnostics/mod.rs b/compiler/rustc_borrowck/src/diagnostics/mod.rs index 3ee0369c9da6e..ab2c3bdba85f5 100644 --- a/compiler/rustc_borrowck/src/diagnostics/mod.rs +++ b/compiler/rustc_borrowck/src/diagnostics/mod.rs @@ -602,8 +602,14 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> { BorrowedContentSource::DerefRawPointer } else if base_ty.is_mutable_ptr() { BorrowedContentSource::DerefMutableRef - } else { + } else if base_ty.is_ref() { BorrowedContentSource::DerefSharedRef + } else { + // Custom type implementing `Deref` (e.g. `MyBox`, `Rc`, `Arc`) + // that wasn't detected via the MIR init trace above. This can happen + // when the deref base is initialized by a regular statement rather than + // a `TerminatorKind::Call` with `CallSource::OverloadedOperator`. + BorrowedContentSource::OverloadedDeref(base_ty) } } @@ -1002,10 +1008,12 @@ struct CapturedMessageOpt { maybe_reinitialized_locations_is_empty: bool, } -/// Tracks which suggestions were emitted by [`MirBorrowckCtxt::explain_captures`], -/// so callers can avoid emitting redundant suggestions downstream. -struct ExplainCapturesResult { - clone_suggestion: bool, +/// Tracks whether [`MirBorrowckCtxt::explain_captures`] emitted a clone +/// suggestion, so callers can avoid emitting redundant suggestions downstream. +#[derive(Copy, Clone, PartialEq, Eq)] +pub(super) enum CloneSuggestion { + Emitted, + NotEmitted, } impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> { @@ -1232,7 +1240,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> { move_spans: UseSpans<'tcx>, moved_place: Place<'tcx>, msg_opt: CapturedMessageOpt, - ) -> ExplainCapturesResult { + ) -> CloneSuggestion { let CapturedMessageOpt { is_partial_move: is_partial, is_loop_message, @@ -1596,7 +1604,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> { }) } } - ExplainCapturesResult { clone_suggestion: suggested_cloning } + if suggested_cloning { CloneSuggestion::Emitted } else { CloneSuggestion::NotEmitted } } /// Skip over locals that begin with an underscore or have no name diff --git a/compiler/rustc_borrowck/src/diagnostics/move_errors.rs b/compiler/rustc_borrowck/src/diagnostics/move_errors.rs index 1dfd83956e49b..9aa0bc1b745d6 100644 --- a/compiler/rustc_borrowck/src/diagnostics/move_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/move_errors.rs @@ -14,7 +14,9 @@ use rustc_trait_selection::infer::InferCtxtExt; use tracing::debug; use crate::MirBorrowckCtxt; -use crate::diagnostics::{CapturedMessageOpt, DescribePlaceOpt, UseSpans}; +use crate::diagnostics::{ + BorrowedContentSource, CapturedMessageOpt, CloneSuggestion, DescribePlaceOpt, UseSpans, +}; use crate::prefixes::PrefixSet; #[derive(Debug)] @@ -270,7 +272,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> { return; } - let mut has_clone_suggestion = false; + let mut has_clone_suggestion = CloneSuggestion::NotEmitted; let mut err = match kind { &IllegalMoveOriginKind::BorrowedContent { target_place } => { let (diag, clone_sugg) = self.report_cannot_move_from_borrowed_content( @@ -431,7 +433,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> { deref_target_place: Place<'tcx>, span: Span, use_spans: Option>, - ) -> (Diag<'infcx>, bool) { + ) -> (Diag<'infcx>, CloneSuggestion) { let tcx = self.infcx.tcx; // Inspect the type of the content behind the // borrow to provide feedback about why this @@ -464,10 +466,13 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> { "variables bound in patterns cannot be moved from \ until after the end of the pattern guard", ), - false, + CloneSuggestion::NotEmitted, ); } else if decl.is_ref_to_static() { - return (self.report_cannot_move_from_static(move_place, span), false); + return ( + self.report_cannot_move_from_static(move_place, span), + CloneSuggestion::NotEmitted, + ); } } @@ -548,9 +553,8 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> { }; let suggested_cloning = if let Some(use_spans) = use_spans { self.explain_captures(&mut err, span, span, use_spans, move_place, msg_opt) - .clone_suggestion } else { - false + CloneSuggestion::NotEmitted }; (err, suggested_cloning) } @@ -686,12 +690,48 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> { } } + /// Suggest cloning via UFCS when a move occurs through a custom `Deref` impl. + /// + /// A simple `.clone()` on a type like `MyBox>` would clone the wrapper, + /// not the inner `Vec`. Instead, we suggest ` as Clone>::clone(&val)`. + fn suggest_cloning_through_overloaded_deref( + &self, + err: &mut Diag<'_>, + ty: Ty<'tcx>, + span: Span, + ) -> CloneSuggestion { + let tcx = self.infcx.tcx; + let Some(clone_trait) = tcx.lang_items().clone_trait() else { + return CloneSuggestion::NotEmitted; + }; + let Some(errors) = + self.infcx.type_implements_trait_shallow(clone_trait, ty, self.infcx.param_env) + else { + return CloneSuggestion::NotEmitted; + }; + + if !errors.is_empty() { + return CloneSuggestion::NotEmitted; + } + let sugg = vec![ + (span.shrink_to_lo(), format!("<{ty} as Clone>::clone(&")), + (span.shrink_to_hi(), ")".to_string()), + ]; + err.multipart_suggestion( + "you can `clone` the value and consume it, but this might not be \ + your desired behavior", + sugg, + Applicability::MaybeIncorrect, + ); + CloneSuggestion::Emitted + } + fn add_move_hints( &self, error: GroupedMoveError<'tcx>, err: &mut Diag<'_>, span: Span, - has_clone_suggestion: bool, + has_clone_suggestion: CloneSuggestion, ) { match error { GroupedMoveError::MovesFromPlace { mut binds_to, move_from, .. } => { @@ -735,15 +775,42 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> { None => "value".to_string(), }; - if !has_clone_suggestion { - if let Some(expr) = self.find_expr(use_span) { - self.suggest_cloning( - err, - original_path.as_ref(), - place_ty, - expr, - Some(use_spans), - ); + if has_clone_suggestion == CloneSuggestion::NotEmitted { + // Check if the move is directly through a custom Deref impl + // (e.g. `*my_box` where MyBox implements Deref). + // A simple `.clone()` would clone the wrapper type rather than + // the inner value, so we need a UFCS suggestion instead. + // + // However, if there are further projections after the deref + // (e.g. `(*rc).field`), the value accessed is already the inner + // type and a simple `.clone()` works correctly. + let needs_ufcs = original_path.projection.last() + == Some(&ProjectionElem::Deref) + && original_path.iter_projections().any(|(place, elem)| { + matches!(elem, ProjectionElem::Deref) + && matches!( + self.borrowed_content_source(place), + BorrowedContentSource::OverloadedDeref(_) + | BorrowedContentSource::OverloadedIndex(_) + ) + }); + + let emitted_ufcs = if needs_ufcs { + self.suggest_cloning_through_overloaded_deref(err, place_ty, use_span) + } else { + CloneSuggestion::NotEmitted + }; + + if emitted_ufcs == CloneSuggestion::NotEmitted { + if let Some(expr) = self.find_expr(use_span) { + self.suggest_cloning( + err, + original_path.as_ref(), + place_ty, + expr, + Some(use_spans), + ); + } } } diff --git a/tests/ui/suggestions/ufcs-for-deref-inner-clone.fixed b/tests/ui/suggestions/ufcs-for-deref-inner-clone.fixed new file mode 100644 index 0000000000000..de85216e8880c --- /dev/null +++ b/tests/ui/suggestions/ufcs-for-deref-inner-clone.fixed @@ -0,0 +1,16 @@ +//@ run-rustfix +use std::ops::Deref; + +struct MyBox(T); + +impl Deref for MyBox { + type Target = T; + fn deref(&self) -> &Self::Target { + &self.0 + } +} + +pub fn main() { + let _x = as Clone>::clone(&MyBox(vec![1, 2])).into_iter(); + //~^ ERROR cannot move out of dereference of `MyBox>` +} diff --git a/tests/ui/suggestions/ufcs-for-deref-inner-clone.rs b/tests/ui/suggestions/ufcs-for-deref-inner-clone.rs new file mode 100644 index 0000000000000..dc0dd02f97a92 --- /dev/null +++ b/tests/ui/suggestions/ufcs-for-deref-inner-clone.rs @@ -0,0 +1,16 @@ +//@ run-rustfix +use std::ops::Deref; + +struct MyBox(T); + +impl Deref for MyBox { + type Target = T; + fn deref(&self) -> &Self::Target { + &self.0 + } +} + +pub fn main() { + let _x = MyBox(vec![1, 2]).into_iter(); + //~^ ERROR cannot move out of dereference of `MyBox>` +} diff --git a/tests/ui/suggestions/ufcs-for-deref-inner-clone.stderr b/tests/ui/suggestions/ufcs-for-deref-inner-clone.stderr new file mode 100644 index 0000000000000..7fde14f1a61bb --- /dev/null +++ b/tests/ui/suggestions/ufcs-for-deref-inner-clone.stderr @@ -0,0 +1,14 @@ +error[E0507]: cannot move out of dereference of `MyBox>` + --> $DIR/ufcs-for-deref-inner-clone.rs:14:14 + | +LL | let _x = MyBox(vec![1, 2]).into_iter(); + | ^^^^^^^^^^^^^^^^^ move occurs because value has type `Vec`, which does not implement the `Copy` trait + | +help: you can `clone` the value and consume it, but this might not be your desired behavior + | +LL | let _x = as Clone>::clone(&MyBox(vec![1, 2])).into_iter(); + | ++++++++++++++++++++++++++++ + + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0507`. From 0705bbac94679548596165eebb015c5f23609d96 Mon Sep 17 00:00:00 2001 From: Camille Gillot Date: Fri, 17 Apr 2026 20:05:28 +0000 Subject: [PATCH 177/183] Do not modify resolver outputs during lowering Co-authored-by: Camille Gillot --- compiler/rustc_ast_lowering/src/asm.rs | 7 +- compiler/rustc_ast_lowering/src/block.rs | 4 +- compiler/rustc_ast_lowering/src/contract.rs | 4 +- compiler/rustc_ast_lowering/src/delegation.rs | 18 +- .../src/delegation/generics.rs | 12 +- compiler/rustc_ast_lowering/src/expr.rs | 11 +- compiler/rustc_ast_lowering/src/format.rs | 7 +- compiler/rustc_ast_lowering/src/item.rs | 42 ++-- compiler/rustc_ast_lowering/src/lib.rs | 214 +++++------------- compiler/rustc_ast_lowering/src/pat.rs | 9 +- compiler/rustc_ast_lowering/src/path.rs | 5 +- compiler/rustc_middle/src/hir/map.rs | 2 +- compiler/rustc_middle/src/hir/mod.rs | 15 +- compiler/rustc_middle/src/ty/mod.rs | 2 +- compiler/rustc_resolve/src/lib.rs | 7 +- 15 files changed, 121 insertions(+), 238 deletions(-) diff --git a/compiler/rustc_ast_lowering/src/asm.rs b/compiler/rustc_ast_lowering/src/asm.rs index 3a27962feca39..46d7beae8fe58 100644 --- a/compiler/rustc_ast_lowering/src/asm.rs +++ b/compiler/rustc_ast_lowering/src/asm.rs @@ -18,11 +18,9 @@ use super::errors::{ InvalidRegisterClass, RegisterClassOnlyClobber, RegisterClassOnlyClobberStable, RegisterConflict, }; -use crate::{ - AllowReturnTypeNotation, ImplTraitContext, ImplTraitPosition, ParamMode, ResolverAstLoweringExt, -}; +use crate::{AllowReturnTypeNotation, ImplTraitContext, ImplTraitPosition, ParamMode}; -impl<'hir, R: ResolverAstLoweringExt<'hir>> LoweringContext<'_, 'hir, R> { +impl<'hir> LoweringContext<'_, 'hir> { pub(crate) fn lower_inline_asm( &mut self, sp: Span, @@ -203,7 +201,6 @@ impl<'hir, R: ResolverAstLoweringExt<'hir>> LoweringContext<'_, 'hir, R> { }, InlineAsmOperand::Sym { sym } => { let static_def_id = self - .resolver .get_partial_res(sym.id) .and_then(|res| res.full_res()) .and_then(|res| match res { diff --git a/compiler/rustc_ast_lowering/src/block.rs b/compiler/rustc_ast_lowering/src/block.rs index 94839485c6036..c70e7d3872d79 100644 --- a/compiler/rustc_ast_lowering/src/block.rs +++ b/compiler/rustc_ast_lowering/src/block.rs @@ -4,9 +4,9 @@ use rustc_hir::Target; use rustc_span::sym; use smallvec::SmallVec; -use crate::{ImplTraitContext, ImplTraitPosition, LoweringContext, ResolverAstLoweringExt}; +use crate::{ImplTraitContext, ImplTraitPosition, LoweringContext}; -impl<'hir, R: ResolverAstLoweringExt<'hir>> LoweringContext<'_, 'hir, R> { +impl<'hir> LoweringContext<'_, 'hir> { pub(super) fn lower_block( &mut self, b: &Block, diff --git a/compiler/rustc_ast_lowering/src/contract.rs b/compiler/rustc_ast_lowering/src/contract.rs index fd05ed0c78e43..4b2ee21ca5980 100644 --- a/compiler/rustc_ast_lowering/src/contract.rs +++ b/compiler/rustc_ast_lowering/src/contract.rs @@ -2,9 +2,9 @@ use std::sync::Arc; use thin_vec::thin_vec; -use crate::{LoweringContext, ResolverAstLoweringExt}; +use crate::LoweringContext; -impl<'hir, R: ResolverAstLoweringExt<'hir>> LoweringContext<'_, 'hir, R> { +impl<'hir> LoweringContext<'_, 'hir> { /// Lowered contracts are guarded with the `contract_checks` compiler flag, /// i.e. the flag turns into a boolean guard in the lowered HIR. The reason /// for not eliminating the contract code entirely when the `contract_checks` diff --git a/compiler/rustc_ast_lowering/src/delegation.rs b/compiler/rustc_ast_lowering/src/delegation.rs index 3a5b6ad608aa2..354d4188390c3 100644 --- a/compiler/rustc_ast_lowering/src/delegation.rs +++ b/compiler/rustc_ast_lowering/src/delegation.rs @@ -105,7 +105,7 @@ static ATTRS_ADDITIONS: &[AttrAdditionInfo] = &[ }, ]; -impl<'hir, R: ResolverAstLoweringExt<'hir>> LoweringContext<'_, 'hir, R> { +impl<'hir> LoweringContext<'_, 'hir> { fn is_method(&self, def_id: DefId, span: Span) -> bool { match self.tcx.def_kind(def_id) { DefKind::Fn => false, @@ -266,7 +266,7 @@ impl<'hir, R: ResolverAstLoweringExt<'hir>> LoweringContext<'_, 'hir, R> { } fn get_resolution_id(&self, node_id: NodeId) -> Option { - self.resolver.get_partial_res(node_id).and_then(|r| r.expect_full_res().opt_def_id()) + self.get_partial_res(node_id).and_then(|r| r.expect_full_res().opt_def_id()) } // Function parameter count, including C variadic `...` if present. @@ -417,7 +417,7 @@ impl<'hir, R: ResolverAstLoweringExt<'hir>> LoweringContext<'_, 'hir, R> { && idx == 0 { let mut self_resolver = SelfResolver { - resolver: this.resolver, + ctxt: this, path_id: delegation.id, self_param_id: pat_node_id, }; @@ -665,25 +665,25 @@ impl<'hir, R: ResolverAstLoweringExt<'hir>> LoweringContext<'_, 'hir, R> { } } -struct SelfResolver<'a, R> { - resolver: &'a mut R, +struct SelfResolver<'a, 'b, 'hir> { + ctxt: &'a mut LoweringContext<'b, 'hir>, path_id: NodeId, self_param_id: NodeId, } -impl<'tcx, R: ResolverAstLoweringExt<'tcx>> SelfResolver<'_, R> { +impl SelfResolver<'_, '_, '_> { fn try_replace_id(&mut self, id: NodeId) { - if let Some(res) = self.resolver.get_partial_res(id) + if let Some(res) = self.ctxt.get_partial_res(id) && let Some(Res::Local(sig_id)) = res.full_res() && sig_id == self.path_id { let new_res = PartialRes::new(Res::Local(self.self_param_id)); - self.resolver.insert_partial_res(id, new_res); + self.ctxt.partial_res_overrides.insert(id, new_res); } } } -impl<'ast, 'tcx, R: ResolverAstLoweringExt<'tcx>> Visitor<'ast> for SelfResolver<'_, R> { +impl<'ast> Visitor<'ast> for SelfResolver<'_, '_, '_> { fn visit_id(&mut self, id: NodeId) { self.try_replace_id(id); } diff --git a/compiler/rustc_ast_lowering/src/delegation/generics.rs b/compiler/rustc_ast_lowering/src/delegation/generics.rs index 503877cff9785..afffc20adf4b3 100644 --- a/compiler/rustc_ast_lowering/src/delegation/generics.rs +++ b/compiler/rustc_ast_lowering/src/delegation/generics.rs @@ -8,7 +8,7 @@ use rustc_middle::{bug, ty}; use rustc_span::symbol::kw; use rustc_span::{Ident, Span, sym}; -use crate::{LoweringContext, ResolverAstLoweringExt}; +use crate::LoweringContext; #[derive(Clone, Copy)] pub(super) enum DelegationGenericsKind { @@ -114,7 +114,7 @@ impl DelegationGenericsKind { impl<'hir> HirOrTyGenerics<'hir> { pub(super) fn into_hir_generics( &mut self, - ctx: &mut LoweringContext<'_, 'hir, impl ResolverAstLoweringExt<'hir>>, + ctx: &mut LoweringContext<'_, 'hir>, span: Span, ) -> &mut HirOrTyGenerics<'hir> { if let HirOrTyGenerics::Ty(ty) = self { @@ -140,7 +140,7 @@ impl<'hir> HirOrTyGenerics<'hir> { pub(super) fn into_generic_args( &self, - ctx: &mut LoweringContext<'_, 'hir, impl ResolverAstLoweringExt<'hir>>, + ctx: &mut LoweringContext<'_, 'hir>, span: Span, ) -> &'hir hir::GenericArgs<'hir> { match self { @@ -174,7 +174,7 @@ impl<'hir> GenericsGenerationResults<'hir> { pub(super) fn all_params( &mut self, span: Span, - ctx: &mut LoweringContext<'_, 'hir, impl ResolverAstLoweringExt<'hir>>, + ctx: &mut LoweringContext<'_, 'hir>, ) -> impl Iterator> { // Now we always call `into_hir_generics` both on child and parent, // however in future we would not do that, when scenarios like @@ -208,7 +208,7 @@ impl<'hir> GenericsGenerationResults<'hir> { pub(super) fn all_predicates( &mut self, span: Span, - ctx: &mut LoweringContext<'_, 'hir, impl ResolverAstLoweringExt<'hir>>, + ctx: &mut LoweringContext<'_, 'hir>, ) -> impl Iterator> { // Now we always call `into_hir_generics` both on child and parent, // however in future we would not do that, when scenarios like @@ -226,7 +226,7 @@ impl<'hir> GenericsGenerationResults<'hir> { } } -impl<'hir, R: ResolverAstLoweringExt<'hir>> LoweringContext<'_, 'hir, R> { +impl<'hir> LoweringContext<'_, 'hir> { pub(super) fn uplift_delegation_generics( &mut self, delegation: &Delegation, diff --git a/compiler/rustc_ast_lowering/src/expr.rs b/compiler/rustc_ast_lowering/src/expr.rs index aad838e9a1728..f0b292d3179da 100644 --- a/compiler/rustc_ast_lowering/src/expr.rs +++ b/compiler/rustc_ast_lowering/src/expr.rs @@ -51,7 +51,7 @@ impl<'v> rustc_ast::visit::Visitor<'v> for WillCreateDefIdsVisitor { } } -impl<'hir, R: ResolverAstLoweringExt<'hir>> LoweringContext<'_, 'hir, R> { +impl<'hir> LoweringContext<'_, 'hir> { fn lower_exprs(&mut self, exprs: &[Box]) -> &'hir [hir::Expr<'hir>] { self.arena.alloc_from_iter(exprs.iter().map(|x| self.lower_expr_mut(x))) } @@ -1235,10 +1235,7 @@ impl<'hir, R: ResolverAstLoweringExt<'hir>> LoweringContext<'_, 'hir, R> { whole_span: Span, ) -> hir::ExprKind<'hir> { // Return early in case of an ordinary assignment. - fn is_ordinary<'hir>( - lower_ctx: &mut LoweringContext<'_, 'hir, impl ResolverAstLoweringExt<'hir>>, - lhs: &Expr, - ) -> bool { + fn is_ordinary(lower_ctx: &mut LoweringContext<'_, '_>, lhs: &Expr) -> bool { match &lhs.kind { ExprKind::Array(..) | ExprKind::Struct(..) @@ -1293,7 +1290,7 @@ impl<'hir, R: ResolverAstLoweringExt<'hir>> LoweringContext<'_, 'hir, R> { ) -> Option<(&'a Option>, &'a Path)> { if let ExprKind::Path(qself, path) = &expr.kind { // Does the path resolve to something disallowed in a tuple struct/variant pattern? - if let Some(partial_res) = self.resolver.get_partial_res(expr.id) { + if let Some(partial_res) = self.get_partial_res(expr.id) { if let Some(res) = partial_res.full_res() && !res.expected_in_tuple_struct_pat() { @@ -1315,7 +1312,7 @@ impl<'hir, R: ResolverAstLoweringExt<'hir>> LoweringContext<'_, 'hir, R> { ) -> Option<(&'a Option>, &'a Path)> { if let ExprKind::Path(qself, path) = &expr.kind { // Does the path resolve to something disallowed in a unit struct/variant pattern? - if let Some(partial_res) = self.resolver.get_partial_res(expr.id) { + if let Some(partial_res) = self.get_partial_res(expr.id) { if let Some(res) = partial_res.full_res() && !res.expected_in_unit_struct_pat() { diff --git a/compiler/rustc_ast_lowering/src/format.rs b/compiler/rustc_ast_lowering/src/format.rs index 1f1f86f7edfd7..602635af1324e 100644 --- a/compiler/rustc_ast_lowering/src/format.rs +++ b/compiler/rustc_ast_lowering/src/format.rs @@ -7,9 +7,8 @@ use rustc_session::config::FmtDebug; use rustc_span::{ByteSymbol, DesugaringKind, Ident, Span, Symbol, sym}; use super::LoweringContext; -use crate::ResolverAstLoweringExt; -impl<'hir, R: ResolverAstLoweringExt<'hir>> LoweringContext<'_, 'hir, R> { +impl<'hir> LoweringContext<'_, 'hir> { pub(crate) fn lower_format_args(&mut self, sp: Span, fmt: &FormatArgs) -> hir::ExprKind<'hir> { // Never call the const constructor of `fmt::Arguments` if the // format_args!() had any arguments _before_ flattening/inlining. @@ -231,7 +230,7 @@ enum ArgumentType { /// ::new_…(arg) /// ``` fn make_argument<'hir>( - ctx: &mut LoweringContext<'_, 'hir, impl ResolverAstLoweringExt<'hir>>, + ctx: &mut LoweringContext<'_, 'hir>, sp: Span, arg: &'hir hir::Expr<'hir>, ty: ArgumentType, @@ -278,7 +277,7 @@ fn make_count( } fn expand_format_args<'hir>( - ctx: &mut LoweringContext<'_, 'hir, impl ResolverAstLoweringExt<'hir>>, + ctx: &mut LoweringContext<'_, 'hir>, macsp: Span, fmt: &FormatArgs, allow_const: bool, diff --git a/compiler/rustc_ast_lowering/src/item.rs b/compiler/rustc_ast_lowering/src/item.rs index e8ddf5bea1795..2195581eccec3 100644 --- a/compiler/rustc_ast_lowering/src/item.rs +++ b/compiler/rustc_ast_lowering/src/item.rs @@ -1,22 +1,19 @@ use std::mem; -use std::sync::Arc; use rustc_abi::ExternAbi; use rustc_ast::visit::AssocCtxt; use rustc_ast::*; use rustc_data_structures::fx::FxIndexMap; -use rustc_data_structures::steal::Steal; use rustc_errors::{E0570, ErrorGuaranteed, struct_span_code_err}; use rustc_hir::attrs::{AttributeKind, EiiImplResolution}; use rustc_hir::def::{DefKind, PerNS, Res}; -use rustc_hir::def_id::{CRATE_DEF_ID, LocalDefId, LocalDefIdMap}; -use rustc_hir::definitions::PerParentDisambiguatorState; +use rustc_hir::def_id::{CRATE_DEF_ID, LocalDefId}; use rustc_hir::{ self as hir, HirId, ImplItemImplKind, LifetimeSource, PredicateOrigin, Target, find_attr, }; use rustc_index::{IndexSlice, IndexVec}; use rustc_middle::span_bug; -use rustc_middle::ty::TyCtxt; +use rustc_middle::ty::{ResolverAstLowering, TyCtxt}; use rustc_span::def_id::DefId; use rustc_span::edit_distance::find_best_match_for_name; use rustc_span::{DUMMY_SP, DesugaringKind, Ident, Span, Symbol, kw, sym}; @@ -51,21 +48,11 @@ impl<'hir> Owners<'_, 'hir> { } } -/// Default disambiguators are used during default lowering, when we lower -/// AST owners in a loop we can use the whole map, in contrast delayed lowering -/// lowers each AST owner separately, so we use readonly disambiguators map -/// with `Steal`s to get disambiguators. -pub(super) enum Disambiguators { - Default(LocalDefIdMap), - Delayed(Arc>>), -} - -pub(super) struct ItemLowerer<'a, 'hir, R> { +pub(super) struct ItemLowerer<'a, 'hir> { pub(super) tcx: TyCtxt<'hir>, - pub(super) resolver: &'a mut R, + pub(super) resolver: &'a ResolverAstLowering<'hir>, pub(super) ast_index: &'a IndexSlice>, pub(super) owners: Owners<'a, 'hir>, - pub(super) disambiguators: &'a mut Disambiguators, } /// When we have a ty alias we *may* have two where clauses. To give the best diagnostics, we set the span @@ -87,13 +74,13 @@ fn add_ty_alias_where_clause( if before.0 || !after.0 { before } else { after }; } -impl<'hir, R: ResolverAstLoweringExt<'hir>> ItemLowerer<'_, 'hir, R> { +impl<'hir> ItemLowerer<'_, 'hir> { fn with_lctx( &mut self, owner: NodeId, - f: impl FnOnce(&mut LoweringContext<'_, 'hir, R>) -> hir::OwnerNode<'hir>, + f: impl for<'a> FnOnce(&mut LoweringContext<'a, 'hir>) -> hir::OwnerNode<'hir>, ) { - let mut lctx = LoweringContext::new(self.tcx, self.resolver, self.disambiguators); + let mut lctx = LoweringContext::new(self.tcx, self.resolver); lctx.with_hir_id_owner(owner, |lctx| f(lctx)); for (def_id, info) in lctx.children { @@ -135,7 +122,7 @@ impl<'hir, R: ResolverAstLoweringExt<'hir>> ItemLowerer<'_, 'hir, R> { } } -impl<'hir, R: ResolverAstLoweringExt<'hir>> LoweringContext<'_, 'hir, R> { +impl<'hir> LoweringContext<'_, 'hir> { pub(super) fn lower_mod( &mut self, items: &[Box], @@ -648,7 +635,7 @@ impl<'hir, R: ResolverAstLoweringExt<'hir>> LoweringContext<'_, 'hir, R> { } fn lower_path_simple_eii(&mut self, id: NodeId, path: &Path) -> Option { - let res = self.resolver.get_partial_res(id)?; + let res = self.get_partial_res(id)?; let Some(did) = res.expect_full_res().opt_def_id() else { self.dcx().span_delayed_bug(path.span, "should have errored in resolve"); return None; @@ -1349,7 +1336,6 @@ impl<'hir, R: ResolverAstLoweringExt<'hir>> LoweringContext<'_, 'hir, R> { ImplItemImplKind::Trait { defaultness, trait_item_def_id: self - .resolver .get_partial_res(i.id) .and_then(|r| r.expect_full_res().opt_def_id()) .ok_or_else(|| { @@ -1545,7 +1531,7 @@ impl<'hir, R: ResolverAstLoweringExt<'hir>> LoweringContext<'_, 'hir, R> { pub(crate) fn lower_coroutine_body_with_moved_arguments( &mut self, decl: &FnDecl, - lower_body: impl FnOnce(&mut LoweringContext<'_, 'hir, R>) -> hir::Expr<'hir>, + lower_body: impl FnOnce(&mut LoweringContext<'_, 'hir>) -> hir::Expr<'hir>, fn_decl_span: Span, body_span: Span, coroutine_kind: CoroutineKind, @@ -1682,7 +1668,7 @@ impl<'hir, R: ResolverAstLoweringExt<'hir>> LoweringContext<'_, 'hir, R> { parameters.push(new_parameter); } - let mkbody = |this: &mut LoweringContext<'_, 'hir, R>| { + let mkbody = |this: &mut LoweringContext<'_, 'hir>| { // Create a block from the user's function body: let user_body = lower_body(this); @@ -1867,7 +1853,7 @@ impl<'hir, R: ResolverAstLoweringExt<'hir>> LoweringContext<'_, 'hir, R> { let kind = match &r.kind { RestrictionKind::Unrestricted => hir::RestrictionKind::Unrestricted, RestrictionKind::Restricted { path, id, shorthand: _ } => { - let res = self.resolver.get_partial_res(*id); + let res = self.get_partial_res(*id); if let Some(did) = res.and_then(|res| res.expect_full_res().opt_def_id()) { hir::RestrictionKind::Restricted(self.arena.alloc(hir::Path { res: did, @@ -1933,7 +1919,7 @@ impl<'hir, R: ResolverAstLoweringExt<'hir>> LoweringContext<'_, 'hir, R> { // Introduce extra lifetimes if late resolution tells us to. let extra_lifetimes = self.resolver.extra_lifetime_params(parent_node_id); - params.extend(extra_lifetimes.into_iter().filter_map(|(ident, node_id, res)| { + params.extend(extra_lifetimes.into_iter().filter_map(|&(ident, node_id, res)| { self.lifetime_res_to_generic_param( ident, node_id, @@ -1975,7 +1961,7 @@ impl<'hir, R: ResolverAstLoweringExt<'hir>> LoweringContext<'_, 'hir, R> { return; }; let define_opaque = define_opaque.iter().filter_map(|(id, path)| { - let res = self.resolver.get_partial_res(*id); + let res = self.get_partial_res(*id); let Some(did) = res.and_then(|res| res.expect_full_res().opt_def_id()) else { self.dcx().span_delayed_bug(path.span, "should have errored in resolve"); return None; diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs index bf773301ed4b5..906c44c8240ab 100644 --- a/compiler/rustc_ast_lowering/src/lib.rs +++ b/compiler/rustc_ast_lowering/src/lib.rs @@ -70,7 +70,7 @@ use thin_vec::ThinVec; use tracing::{debug, instrument, trace}; use crate::errors::{AssocTyParentheses, AssocTyParenthesesSub, MisplacedImplTrait}; -use crate::item::{Disambiguators, Owners}; +use crate::item::Owners; macro_rules! arena_vec { ($this:expr; $($x:expr),*) => ( @@ -91,10 +91,9 @@ mod pat; mod path; pub mod stability; -struct LoweringContext<'a, 'hir, R> { +struct LoweringContext<'a, 'hir> { tcx: TyCtxt<'hir>, - resolver: &'a mut R, - disambiguators: &'a mut Disambiguators, + resolver: &'a ResolverAstLowering<'hir>, current_disambiguator: PerParentDisambiguatorState, /// Used to allocate HIR nodes. @@ -139,6 +138,14 @@ struct LoweringContext<'a, 'hir, R> { /// NodeIds that are lowered inside the current HIR owner. Only used for duplicate lowering check. #[cfg(debug_assertions)] node_id_to_local_id: NodeMap, + /// The `NodeId` space is split in two. + /// `0..resolver.next_node_id` are created by the resolver on the AST. + /// The higher part `resolver.next_node_id..next_node_id` are created during lowering. + next_node_id: NodeId, + /// Maps the `NodeId`s created during lowering to `LocalDefId`s. + node_id_to_def_id: NodeMap, + /// Overlay over resolver's `partial_res_map` used by delegation. + partial_res_overrides: NodeMap, allow_contracts: Arc<[Symbol]>, allow_try_trait: Arc<[Symbol]>, @@ -154,13 +161,12 @@ struct LoweringContext<'a, 'hir, R> { attribute_parser: AttributeParser<'hir>, } -impl<'a, 'hir, R: ResolverAstLoweringExt<'hir>> LoweringContext<'a, 'hir, R> { - fn new(tcx: TyCtxt<'hir>, resolver: &'a mut R, disambiguators: &'a mut Disambiguators) -> Self { +impl<'a, 'hir> LoweringContext<'a, 'hir> { + fn new(tcx: TyCtxt<'hir>, resolver: &'a ResolverAstLowering<'hir>) -> Self { let registered_tools = tcx.registered_tools(()).iter().map(|x| x.name).collect(); Self { tcx, resolver, - disambiguators, current_disambiguator: Default::default(), arena: tcx.hir_arena, @@ -176,6 +182,9 @@ impl<'a, 'hir, R: ResolverAstLoweringExt<'hir>> LoweringContext<'a, 'hir, R> { #[cfg(debug_assertions)] node_id_to_local_id: Default::default(), trait_map: Default::default(), + next_node_id: resolver.next_node_id, + node_id_to_def_id: NodeMap::default(), + partial_res_overrides: NodeMap::default(), // Lowering state. try_block_scope: TryBlockScope::Function, @@ -239,81 +248,6 @@ impl SpanLowerer { } } -struct ResolverDelayedAstLowering<'a, 'tcx> { - node_id_to_def_id: NodeMap, - partial_res_map: NodeMap, - next_node_id: NodeId, - base: &'a ResolverAstLowering<'tcx>, -} - -// FIXME(fn_delegation): delegate this trait impl to `self.base` -impl<'a, 'tcx> ResolverAstLoweringExt<'tcx> for ResolverDelayedAstLowering<'a, 'tcx> { - fn legacy_const_generic_args(&self, expr: &Expr, tcx: TyCtxt<'tcx>) -> Option> { - self.base.legacy_const_generic_args(expr, tcx) - } - - fn get_partial_res(&self, id: NodeId) -> Option { - self.partial_res_map.get(&id).copied().or_else(|| self.base.get_partial_res(id)) - } - - fn get_import_res(&self, id: NodeId) -> PerNS>> { - self.base.get_import_res(id) - } - - fn get_label_res(&self, id: NodeId) -> Option { - self.base.get_label_res(id) - } - - fn get_lifetime_res(&self, id: NodeId) -> Option { - self.base.get_lifetime_res(id) - } - - fn extra_lifetime_params(&self, id: NodeId) -> Vec<(Ident, NodeId, LifetimeRes)> { - self.base.extra_lifetime_params(id) - } - - fn delegation_info(&self, id: LocalDefId) -> Option<&DelegationInfo> { - self.base.delegation_info(id) - } - - fn opt_local_def_id(&self, id: NodeId) -> Option { - self.node_id_to_def_id.get(&id).copied().or_else(|| self.base.opt_local_def_id(id)) - } - - fn local_def_id(&self, id: NodeId) -> LocalDefId { - self.opt_local_def_id(id).expect("must have def_id") - } - - fn lifetime_elision_allowed(&self, id: NodeId) -> bool { - self.base.lifetime_elision_allowed(id) - } - - fn insert_new_def_id(&mut self, node_id: NodeId, def_id: LocalDefId) { - self.node_id_to_def_id.insert(node_id, def_id); - } - - fn insert_partial_res(&mut self, node_id: NodeId, res: PartialRes) { - self.partial_res_map.insert(node_id, res); - } - - fn trait_candidates(&self, node_id: NodeId) -> Option<&'tcx [hir::TraitCandidate<'tcx>]> { - self.base.trait_candidates(node_id) - } - - #[inline] - fn next_node_id(&mut self) -> NodeId { - next_node_id(&mut self.next_node_id) - } -} - -fn next_node_id(current_id: &mut NodeId) -> NodeId { - let start = *current_id; - let next = start.as_u32().checked_add(1).expect("input too large; ran out of NodeIds"); - *current_id = ast::NodeId::from_u32(next); - - start -} - #[extension(trait ResolverAstLoweringExt<'tcx>)] impl<'tcx> ResolverAstLowering<'tcx> { fn legacy_const_generic_args(&self, expr: &Expr, tcx: TyCtxt<'tcx>) -> Option> { @@ -327,7 +261,7 @@ impl<'tcx> ResolverAstLowering<'tcx> { return None; } - let def_id = self.get_partial_res(expr.id)?.full_res()?.opt_def_id()?; + let def_id = self.partial_res_map.get(&expr.id)?.full_res()?.opt_def_id()?; // We only support cross-crate argument rewriting. Uses // within the same crate should be updated to use the new @@ -344,10 +278,6 @@ impl<'tcx> ResolverAstLowering<'tcx> { .map(|fn_indexes| fn_indexes.iter().map(|(num, _)| *num).collect()) } - fn get_partial_res(&self, id: NodeId) -> Option { - self.partial_res_map.get(&id).copied() - } - /// Obtains per-namespace resolutions for `use` statement with the given `NodeId`. fn get_import_res(&self, id: NodeId) -> PerNS>> { self.import_res_map.get(&id).copied().unwrap_or_default() @@ -370,8 +300,8 @@ impl<'tcx> ResolverAstLowering<'tcx> { /// /// The extra lifetimes that appear from the parenthesized `Fn`-trait desugaring /// should appear at the enclosing `PolyTraitRef`. - fn extra_lifetime_params(&self, id: NodeId) -> Vec<(Ident, NodeId, LifetimeRes)> { - self.extra_lifetime_params_map.get(&id).cloned().unwrap_or_default() + fn extra_lifetime_params(&self, id: NodeId) -> &[(Ident, NodeId, LifetimeRes)] { + self.extra_lifetime_params_map.get(&id).map_or(&[], |v| &v[..]) } fn delegation_info(&self, id: LocalDefId) -> Option<&DelegationInfo> { @@ -389,23 +319,6 @@ impl<'tcx> ResolverAstLowering<'tcx> { fn lifetime_elision_allowed(&self, id: NodeId) -> bool { self.lifetime_elision_allowed.contains(&id) } - - fn insert_new_def_id(&mut self, node_id: NodeId, def_id: LocalDefId) { - self.node_id_to_def_id.insert(node_id, def_id); - } - - fn insert_partial_res(&mut self, node_id: NodeId, res: PartialRes) { - self.partial_res_map.insert(node_id, res); - } - - fn trait_candidates(&self, node_id: NodeId) -> Option<&'tcx [hir::TraitCandidate<'tcx>]> { - self.trait_map.get(&node_id).copied() - } - - #[inline] - fn next_node_id(&mut self) -> NodeId { - next_node_id(&mut self.next_node_id) - } } /// How relaxed bounds `?Trait` should be treated. @@ -546,7 +459,7 @@ enum TryBlockScope { } fn index_crate<'a, 'b>( - resolver: &'b impl ResolverAstLoweringExt<'a>, + resolver: &'b ResolverAstLowering<'b>, krate: &'a Crate, ) -> IndexVec> { let mut indexer = Indexer { resolver, index: IndexVec::new() }; @@ -556,12 +469,12 @@ fn index_crate<'a, 'b>( return indexer.index; - struct Indexer<'a, 'b, R> { - resolver: &'b R, + struct Indexer<'a, 'b> { + resolver: &'b ResolverAstLowering<'b>, index: IndexVec>, } - impl<'a, 'b, R: ResolverAstLoweringExt<'a>> visit::Visitor<'a> for Indexer<'a, 'b, R> { + impl<'a, 'b> visit::Visitor<'a> for Indexer<'a, 'b> { fn visit_attribute(&mut self, _: &'a Attribute) { // We do not want to lower expressions that appear in attributes, // as they are not accessible to the rest of the HIR. @@ -618,7 +531,7 @@ pub fn lower_to_hir(tcx: TyCtxt<'_>, (): ()) -> mid_hir::Crate<'_> { tcx.ensure_done().early_lint_checks(()); tcx.ensure_done().debugger_visualizers(LOCAL_CRATE); tcx.ensure_done().get_lang_items(()); - let (mut resolver, krate) = tcx.resolver_for_lowering().steal(); + let (resolver, krate) = tcx.resolver_for_lowering().steal(); let ast_index = index_crate(&resolver, &krate); let mut owners = IndexVec::from_fn_n( @@ -626,13 +539,11 @@ pub fn lower_to_hir(tcx: TyCtxt<'_>, (): ()) -> mid_hir::Crate<'_> { tcx.definitions_untracked().def_index_count(), ); - let mut disambiguators = Disambiguators::Default(resolver.disambiguators.steal()); let mut lowerer = item::ItemLowerer { tcx, - resolver: &mut resolver, + resolver: &resolver, ast_index: &ast_index, owners: Owners::IndexVec(&mut owners), - disambiguators: &mut disambiguators, }; let mut delayed_ids: FxIndexSet = Default::default(); @@ -651,11 +562,7 @@ pub fn lower_to_hir(tcx: TyCtxt<'_>, (): ()) -> mid_hir::Crate<'_> { let opt_hir_hash = if tcx.needs_crate_hash() { Some(compute_hir_hash(tcx, &owners)) } else { None }; - let Disambiguators::Default(disambiguators) = disambiguators else { unreachable!() }; - let delayed_disambigs = - Arc::new(disambiguators.into_items().map(|(id, d)| (id, Steal::new(d))).collect()); - - let delayed_resolver = Steal::new((resolver, krate, delayed_disambigs)); + let delayed_resolver = Steal::new((resolver, krate)); mid_hir::Crate::new(owners, delayed_ids, delayed_resolver, opt_hir_hash) } @@ -663,26 +570,18 @@ pub fn lower_to_hir(tcx: TyCtxt<'_>, (): ()) -> mid_hir::Crate<'_> { pub fn lower_delayed_owner(tcx: TyCtxt<'_>, def_id: LocalDefId) { let krate = tcx.hir_crate(()); - let (resolver, krate, delayed_disambigs) = &*krate.delayed_resolver.borrow(); + let (resolver, krate) = &*krate.delayed_resolver.borrow(); // FIXME!!!(fn_delegation): make ast index lifetime same as resolver, // as it is too bad to reindex whole crate on each delegation lowering. let ast_index = index_crate(resolver, krate); - let mut resolver = ResolverDelayedAstLowering { - next_node_id: resolver.next_node_id, - partial_res_map: Default::default(), - node_id_to_def_id: Default::default(), - base: resolver, - }; - let mut map = Default::default(); let mut lowerer = item::ItemLowerer { tcx, - resolver: &mut resolver, + resolver: &resolver, ast_index: &ast_index, owners: Owners::Map(&mut map), - disambiguators: &mut Disambiguators::Delayed(Arc::clone(delayed_disambigs)), }; lowerer.lower_node(def_id); @@ -719,7 +618,7 @@ enum GenericArgsMode { Silence, } -impl<'hir, R: ResolverAstLoweringExt<'hir>> LoweringContext<'_, 'hir, R> { +impl<'hir> LoweringContext<'_, 'hir> { fn create_def( &mut self, node_id: ast::NodeId, @@ -744,25 +643,38 @@ impl<'hir, R: ResolverAstLoweringExt<'hir>> LoweringContext<'_, 'hir, R> { .def_id(); debug!("create_def: def_id_to_node_id[{:?}] <-> {:?}", def_id, node_id); - self.resolver.insert_new_def_id(node_id, def_id); + self.node_id_to_def_id.insert(node_id, def_id); def_id } fn next_node_id(&mut self) -> NodeId { - self.resolver.next_node_id() + let start = self.next_node_id; + let next = start.as_u32().checked_add(1).expect("input too large; ran out of NodeIds"); + self.next_node_id = ast::NodeId::from_u32(next); + start } /// Given the id of some node in the AST, finds the `LocalDefId` associated with it by the name /// resolver (if any). fn opt_local_def_id(&self, node: NodeId) -> Option { - self.resolver.opt_local_def_id(node) + self.node_id_to_def_id + .get(&node) + .or_else(|| self.resolver.node_id_to_def_id.get(&node)) + .copied() } fn local_def_id(&self, node: NodeId) -> LocalDefId { self.opt_local_def_id(node).unwrap_or_else(|| panic!("no entry for node id: `{node:?}`")) } + fn get_partial_res(&self, id: NodeId) -> Option { + self.partial_res_overrides + .get(&id) + .or_else(|| self.resolver.partial_res_map.get(&id)) + .copied() + } + /// Given the id of an owner node in the AST, returns the corresponding `OwnerId`. fn owner_id(&self, node: NodeId) -> hir::OwnerId { hir::OwnerId { def_id: self.local_def_id(node) } @@ -782,12 +694,12 @@ impl<'hir, R: ResolverAstLoweringExt<'hir>> LoweringContext<'_, 'hir, R> { let owner_id = self.owner_id(owner); let def_id = owner_id.def_id; - let new_disambig = match &mut self.disambiguators { - Disambiguators::Default(map) => map.remove(&def_id), - Disambiguators::Delayed(map) => map.get(&def_id).map(Steal::steal), - }; - - let new_disambig = new_disambig.unwrap_or_else(|| PerParentDisambiguatorState::new(def_id)); + let new_disambig = self + .resolver + .disambiguators + .get(&def_id) + .map(|s| s.steal()) + .unwrap_or_else(|| PerParentDisambiguatorState::new(def_id)); let disambiguator = std::mem::replace(&mut self.current_disambiguator, new_disambig); let current_attrs = std::mem::take(&mut self.attrs); @@ -893,8 +805,8 @@ impl<'hir, R: ResolverAstLoweringExt<'hir>> LoweringContext<'_, 'hir, R> { self.children.push((def_id, hir::MaybeOwner::NonOwner(hir_id))); } - if let Some(traits) = self.resolver.trait_candidates(ast_node_id) { - self.trait_map.insert(hir_id.local_id, traits); + if let Some(traits) = self.resolver.trait_map.get(&ast_node_id) { + self.trait_map.insert(hir_id.local_id, &traits[..]); } // Check whether the same `NodeId` is lowered more than once. @@ -935,7 +847,7 @@ impl<'hir, R: ResolverAstLoweringExt<'hir>> LoweringContext<'_, 'hir, R> { } fn expect_full_res(&mut self, id: NodeId) -> Res { - self.resolver.get_partial_res(id).map_or(Res::Err, |pr| pr.expect_full_res()) + self.get_partial_res(id).map_or(Res::Err, |pr| pr.expect_full_res()) } fn lower_import_res(&mut self, id: NodeId, span: Span) -> PerNS> { @@ -1073,8 +985,8 @@ impl<'hir, R: ResolverAstLoweringExt<'hir>> LoweringContext<'_, 'hir, R> { let extra_lifetimes = self.resolver.extra_lifetime_params(binder); debug!(?extra_lifetimes); let extra_lifetimes: Vec<_> = extra_lifetimes - .into_iter() - .filter_map(|(ident, node_id, res)| { + .iter() + .filter_map(|&(ident, node_id, res)| { self.lifetime_res_to_generic_param( ident, node_id, @@ -1400,7 +1312,6 @@ impl<'hir, R: ResolverAstLoweringExt<'hir>> LoweringContext<'_, 'hir, R> { // FIXME: Should we be handling `(PATH_TO_CONST)`? TyKind::Path(None, path) => { if let Some(res) = self - .resolver .get_partial_res(ty.id) .and_then(|partial_res| partial_res.full_res()) { @@ -1451,7 +1362,7 @@ impl<'hir, R: ResolverAstLoweringExt<'hir>> LoweringContext<'_, 'hir, R> { // The other cases when a qpath should be opportunistically made a trait object are handled // by `ty_path`. if qself.is_none() - && let Some(partial_res) = self.resolver.get_partial_res(t.id) + && let Some(partial_res) = self.get_partial_res(t.id) && let Some(Res::Def(DefKind::Trait | DefKind::TraitAlias, _)) = partial_res.full_res() { let (bounds, lifetime_bound) = self.with_dyn_type_scope(true, |this| { @@ -1805,7 +1716,7 @@ impl<'hir, R: ResolverAstLoweringExt<'hir>> LoweringContext<'_, 'hir, R> { let [segment] = path.segments.as_slice() else { panic!(); }; - let res = self.resolver.get_partial_res(*id).map_or(Res::Err, |partial_res| { + let res = self.get_partial_res(*id).map_or(Res::Err, |partial_res| { partial_res.full_res().expect("no partial res expected for precise capture arg") }); hir::PreciseCapturingArg::Param(hir::PreciseCapturingNonLifetimeArg { @@ -2334,7 +2245,7 @@ impl<'hir, R: ResolverAstLoweringExt<'hir>> LoweringContext<'_, 'hir, R> { match rbp { RelaxedBoundPolicy::Allowed => return, RelaxedBoundPolicy::AllowedIfOnTyParam(id, params) => { - if let Some(res) = self.resolver.get_partial_res(id).and_then(|r| r.full_res()) + if let Some(res) = self.get_partial_res(id).and_then(|r| r.full_res()) && let Res::Def(DefKind::TyParam, def_id) = res && params.iter().any(|p| def_id == self.local_def_id(p.id).to_def_id()) { @@ -2804,7 +2715,7 @@ impl<'hir, R: ResolverAstLoweringExt<'hir>> LoweringContext<'_, 'hir, R> { }; let maybe_res = - self.resolver.get_partial_res(expr.id).and_then(|partial_res| partial_res.full_res()); + self.get_partial_res(expr.id).and_then(|partial_res| partial_res.full_res()); if let ExprKind::Path(qself, path) = &expr.kind && path.is_potential_trivial_const_arg() && matches!(maybe_res, Some(Res::Def(DefKind::ConstParam, _))) @@ -3116,10 +3027,7 @@ impl<'hir> GenericArgsCtor<'hir> { && self.parenthesized == hir::GenericArgsParentheses::No } - fn into_generic_args( - self, - this: &LoweringContext<'_, 'hir, impl ResolverAstLoweringExt<'hir>>, - ) -> &'hir hir::GenericArgs<'hir> { + fn into_generic_args(self, this: &LoweringContext<'_, 'hir>) -> &'hir hir::GenericArgs<'hir> { let ga = hir::GenericArgs { args: this.arena.alloc_from_iter(self.args), constraints: self.constraints, diff --git a/compiler/rustc_ast_lowering/src/pat.rs b/compiler/rustc_ast_lowering/src/pat.rs index 88f038f11d3c0..cf0615b8244e5 100644 --- a/compiler/rustc_ast_lowering/src/pat.rs +++ b/compiler/rustc_ast_lowering/src/pat.rs @@ -10,10 +10,11 @@ use rustc_span::{DesugaringKind, Ident, Span, Spanned, respan}; use super::errors::{ ArbitraryExpressionInPattern, ExtraDoubleDot, MisplacedDoubleDot, SubTupleBinding, }; -use super::{ImplTraitContext, LoweringContext, ParamMode, ResolverAstLoweringExt}; -use crate::{AllowReturnTypeNotation, ImplTraitPosition}; +use super::{ + AllowReturnTypeNotation, ImplTraitContext, ImplTraitPosition, LoweringContext, ParamMode, +}; -impl<'hir, R: ResolverAstLoweringExt<'hir>> LoweringContext<'_, 'hir, R> { +impl<'hir> LoweringContext<'_, 'hir> { pub(crate) fn lower_pat(&mut self, pattern: &Pat) -> &'hir hir::Pat<'hir> { self.arena.alloc(self.lower_pat_mut(pattern)) } @@ -287,7 +288,7 @@ impl<'hir, R: ResolverAstLoweringExt<'hir>> LoweringContext<'_, 'hir, R> { hir_id: hir::HirId, lower_sub: impl FnOnce(&mut Self) -> Option<&'hir hir::Pat<'hir>>, ) -> hir::PatKind<'hir> { - match self.resolver.get_partial_res(p.id).map(|d| d.expect_full_res()) { + match self.get_partial_res(p.id).map(|d| d.expect_full_res()) { // `None` can occur in body-less function signatures res @ (None | Some(Res::Local(_))) => { let binding_id = match res { diff --git a/compiler/rustc_ast_lowering/src/path.rs b/compiler/rustc_ast_lowering/src/path.rs index 139140af3e033..49c5f060e2a1e 100644 --- a/compiler/rustc_ast_lowering/src/path.rs +++ b/compiler/rustc_ast_lowering/src/path.rs @@ -20,7 +20,7 @@ use super::{ LifetimeRes, LoweringContext, ParamMode, ResolverAstLoweringExt, }; -impl<'hir, R: ResolverAstLoweringExt<'hir>> LoweringContext<'_, 'hir, R> { +impl<'hir> LoweringContext<'_, 'hir> { #[instrument(level = "trace", skip(self))] pub(crate) fn lower_qpath( &mut self, @@ -41,8 +41,7 @@ impl<'hir, R: ResolverAstLoweringExt<'hir>> LoweringContext<'_, 'hir, R> { self.lower_ty_alloc(&q.ty, ImplTraitContext::Disallowed(ImplTraitPosition::Path)) }); - let partial_res = - self.resolver.get_partial_res(id).unwrap_or_else(|| PartialRes::new(Res::Err)); + let partial_res = self.get_partial_res(id).unwrap_or_else(|| PartialRes::new(Res::Err)); let base_res = partial_res.base_res(); let unresolved_segments = partial_res.unresolved_segments(); diff --git a/compiler/rustc_middle/src/hir/map.rs b/compiler/rustc_middle/src/hir/map.rs index 4cc0ab6304162..d63034ed1d2bb 100644 --- a/compiler/rustc_middle/src/hir/map.rs +++ b/compiler/rustc_middle/src/hir/map.rs @@ -1261,7 +1261,7 @@ fn force_delayed_owners_lowering(tcx: TyCtxt<'_>) { tcx.ensure_done().lower_delayed_owner(id); } - let (_, krate, _) = krate.delayed_resolver.steal(); + let (_, krate) = krate.delayed_resolver.steal(); let prof = tcx.sess.prof.clone(); // Drop AST to free memory. It can be expensive so try to drop it on a separate thread. diff --git a/compiler/rustc_middle/src/hir/mod.rs b/compiler/rustc_middle/src/hir/mod.rs index c81b0a7182558..7f82b9161fe61 100644 --- a/compiler/rustc_middle/src/hir/mod.rs +++ b/compiler/rustc_middle/src/hir/mod.rs @@ -16,8 +16,7 @@ use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; use rustc_data_structures::steal::Steal; use rustc_data_structures::sync::{DynSend, DynSync, try_par_for_each_in}; use rustc_hir::def::{DefKind, Res}; -use rustc_hir::def_id::{DefId, LocalDefId, LocalDefIdMap, LocalModDefId}; -use rustc_hir::definitions::PerParentDisambiguatorState; +use rustc_hir::def_id::{DefId, LocalDefId, LocalModDefId}; use rustc_hir::*; use rustc_index::IndexVec; use rustc_macros::{Decodable, Encodable, HashStable}; @@ -40,11 +39,7 @@ pub struct Crate<'hir> { pub delayed_ids: FxIndexSet, // The resolver and AST crate which are set in the end of the `hir_crate` query // and then stolen and dropped in `force_delayed_owners_lowering`. - pub delayed_resolver: Steal<( - ResolverAstLowering<'hir>, - Arc, - Arc>>, - )>, + pub delayed_resolver: Steal<(ResolverAstLowering<'hir>, Arc)>, // Only present when incr. comp. is enabled. pub opt_hir_hash: Option, } @@ -53,11 +48,7 @@ impl<'hir> Crate<'hir> { pub fn new( owners: IndexVec>, delayed_ids: FxIndexSet, - delayed_resolver: Steal<( - ResolverAstLowering<'hir>, - Arc, - Arc>>, - )>, + delayed_resolver: Steal<(ResolverAstLowering<'hir>, Arc)>, opt_hir_hash: Option, ) -> Crate<'hir> { Crate { owners, delayed_ids, delayed_resolver, opt_hir_hash } diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs index 59cc6a601bfa8..08356b643613a 100644 --- a/compiler/rustc_middle/src/ty/mod.rs +++ b/compiler/rustc_middle/src/ty/mod.rs @@ -227,7 +227,7 @@ pub struct ResolverAstLowering<'tcx> { // Information about delegations which is used when handling recursive delegations pub delegation_infos: LocalDefIdMap, - pub disambiguators: Steal>, + pub disambiguators: LocalDefIdMap>, } #[derive(Debug)] diff --git a/compiler/rustc_resolve/src/lib.rs b/compiler/rustc_resolve/src/lib.rs index cc9ad46c4dca2..6e15f055c6aca 100644 --- a/compiler/rustc_resolve/src/lib.rs +++ b/compiler/rustc_resolve/src/lib.rs @@ -1908,6 +1908,11 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { Some(StrippedCfgItem { parent_scope, ident: item.ident, cfg: item.cfg }) }) .collect(); + let disambiguators = self + .disambiguators + .into_items() + .map(|(def_id, disamb)| (def_id, Steal::new(disamb))) + .collect(); let global_ctxt = ResolverGlobalCtxt { expn_that_defined, @@ -1939,7 +1944,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { lifetime_elision_allowed: self.lifetime_elision_allowed, lint_buffer: Steal::new(self.lint_buffer), delegation_infos: self.delegation_infos, - disambiguators: Steal::new(self.disambiguators), + disambiguators, }; ResolverOutputs { global_ctxt, ast_lowering } } From 9044aba8e134e26f4bb465b4cb4ac9fb4b615923 Mon Sep 17 00:00:00 2001 From: Camille Gillot Date: Tue, 21 Apr 2026 23:39:20 +0000 Subject: [PATCH 178/183] Use imported NodeId. --- compiler/rustc_ast_lowering/src/lib.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs index 906c44c8240ab..7604b0973ff04 100644 --- a/compiler/rustc_ast_lowering/src/lib.rs +++ b/compiler/rustc_ast_lowering/src/lib.rs @@ -621,7 +621,7 @@ enum GenericArgsMode { impl<'hir> LoweringContext<'_, 'hir> { fn create_def( &mut self, - node_id: ast::NodeId, + node_id: NodeId, name: Option, def_kind: DefKind, span: Span, @@ -651,7 +651,7 @@ impl<'hir> LoweringContext<'_, 'hir> { fn next_node_id(&mut self) -> NodeId { let start = self.next_node_id; let next = start.as_u32().checked_add(1).expect("input too large; ran out of NodeIds"); - self.next_node_id = ast::NodeId::from_u32(next); + self.next_node_id = NodeId::from_u32(next); start } From 4433512e90be0fc8b22b872c0150c2ddd45619e2 Mon Sep 17 00:00:00 2001 From: Camille Gillot Date: Tue, 21 Apr 2026 23:46:17 +0000 Subject: [PATCH 179/183] Lighten and document partial_res_overrides. --- compiler/rustc_ast_lowering/src/delegation.rs | 5 ++--- compiler/rustc_ast_lowering/src/lib.rs | 15 ++++++++++----- 2 files changed, 12 insertions(+), 8 deletions(-) diff --git a/compiler/rustc_ast_lowering/src/delegation.rs b/compiler/rustc_ast_lowering/src/delegation.rs index 354d4188390c3..d390934f3b172 100644 --- a/compiler/rustc_ast_lowering/src/delegation.rs +++ b/compiler/rustc_ast_lowering/src/delegation.rs @@ -39,7 +39,7 @@ use std::iter; use ast::visit::Visitor; -use hir::def::{DefKind, PartialRes, Res}; +use hir::def::{DefKind, Res}; use hir::{BodyId, HirId}; use rustc_abi::ExternAbi; use rustc_ast as ast; @@ -677,8 +677,7 @@ impl SelfResolver<'_, '_, '_> { && let Some(Res::Local(sig_id)) = res.full_res() && sig_id == self.path_id { - let new_res = PartialRes::new(Res::Local(self.self_param_id)); - self.ctxt.partial_res_overrides.insert(id, new_res); + self.ctxt.partial_res_overrides.insert(id, self.self_param_id); } } } diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs index 7604b0973ff04..5188fb8d6aada 100644 --- a/compiler/rustc_ast_lowering/src/lib.rs +++ b/compiler/rustc_ast_lowering/src/lib.rs @@ -145,7 +145,9 @@ struct LoweringContext<'a, 'hir> { /// Maps the `NodeId`s created during lowering to `LocalDefId`s. node_id_to_def_id: NodeMap, /// Overlay over resolver's `partial_res_map` used by delegation. - partial_res_overrides: NodeMap, + /// This only contains `PartialRes::new(Res::Local(self_param_id))`, + /// so we only store `self_param_id`. + partial_res_overrides: NodeMap, allow_contracts: Arc<[Symbol]>, allow_try_trait: Arc<[Symbol]>, @@ -261,6 +263,9 @@ impl<'tcx> ResolverAstLowering<'tcx> { return None; } + // We do not need to look at `partial_res_overrides`. That map only contains overrides for + // `self_param` locals. And here we are looking for the function definition that `expr` + // resolves to. let def_id = self.partial_res_map.get(&expr.id)?.full_res()?.opt_def_id()?; // We only support cross-crate argument rewriting. Uses @@ -669,10 +674,10 @@ impl<'hir> LoweringContext<'_, 'hir> { } fn get_partial_res(&self, id: NodeId) -> Option { - self.partial_res_overrides - .get(&id) - .or_else(|| self.resolver.partial_res_map.get(&id)) - .copied() + match self.partial_res_overrides.get(&id) { + Some(self_param_id) => Some(PartialRes::new(Res::Local(*self_param_id))), + None => self.resolver.partial_res_map.get(&id).copied(), + } } /// Given the id of an owner node in the AST, returns the corresponding `OwnerId`. From f0cb3a7f7d9c3394ea5cbe629f19d30971b80404 Mon Sep 17 00:00:00 2001 From: cypherair <262752927+cypherair@users.noreply.github.com> Date: Sat, 25 Apr 2026 14:59:52 -0700 Subject: [PATCH 180/183] arm64e: set ptrauth ABI subtype on metadata objects --- .../rustc_codegen_ssa/src/back/metadata.rs | 4 ++- .../arm64e-macho-metadata-subtype/metadata.rs | 14 ++++++++ .../arm64e-macho-metadata-subtype/rmake.rs | 34 +++++++++++++++++++ 3 files changed, 51 insertions(+), 1 deletion(-) create mode 100644 tests/run-make/arm64e-macho-metadata-subtype/metadata.rs create mode 100644 tests/run-make/arm64e-macho-metadata-subtype/rmake.rs diff --git a/compiler/rustc_codegen_ssa/src/back/metadata.rs b/compiler/rustc_codegen_ssa/src/back/metadata.rs index cb66dabf507a5..9d477e474697a 100644 --- a/compiler/rustc_codegen_ssa/src/back/metadata.rs +++ b/compiler/rustc_codegen_ssa/src/back/metadata.rs @@ -216,7 +216,9 @@ pub(crate) fn create_object_file(sess: &Session) -> Option= 12, "metadata object is too small for a Mach-O header"); + + let magic = u32::from_le_bytes(bytes[0..4].try_into().unwrap()); + assert_eq!(magic, 0xfeedfacf, "metadata object should use a 64-bit Mach-O header"); + + let subtype = u32::from_le_bytes(bytes[8..12].try_into().unwrap()); + assert_eq!( + subtype, 0x80000002, + "arm64e metadata object should use CPU_SUBTYPE_ARM64E | CPU_SUBTYPE_LIB64" + ); +} From 5abd4ae5824079da36342007908260f35f392156 Mon Sep 17 00:00:00 2001 From: cypherair <262752927+cypherair@users.noreply.github.com> Date: Thu, 23 Apr 2026 18:44:21 -0700 Subject: [PATCH 181/183] bootstrap: handle fork shallow upstream detection --- src/bootstrap/src/core/config/tests.rs | 50 ++++++++++ src/bootstrap/src/utils/tests/git.rs | 9 ++ src/build_helper/src/git.rs | 128 ++++++++++++++++++------- 3 files changed, 152 insertions(+), 35 deletions(-) diff --git a/src/bootstrap/src/core/config/tests.rs b/src/bootstrap/src/core/config/tests.rs index c281aa94f64e6..50903f74733c2 100644 --- a/src/bootstrap/src/core/config/tests.rs +++ b/src/bootstrap/src/core/config/tests.rs @@ -723,6 +723,56 @@ fn test_auto_ci_changed_in_pr() { }); } +#[test] +fn test_push_ci_unchanged_anywhere_uses_nightly_ref() { + git_test(|ctx| { + let sha = ctx.create_upstream_merge(&["a"]); + ctx.set_origin_nightly_ref(&sha); + + ctx.create_branch("feature"); + ctx.modify("b"); + ctx.commit(); + + let src = ctx.check_modifications(&["c"], CiEnv::GitHubActions); + assert_eq!(src, PathFreshness::LastModifiedUpstream { upstream: sha }); + }); +} + +#[test] +fn test_push_ci_changed_in_branch_uses_nightly_ref() { + git_test(|ctx| { + let sha = ctx.create_upstream_merge(&["a"]); + ctx.set_origin_nightly_ref(&sha); + + ctx.create_branch("feature"); + ctx.modify("b"); + ctx.commit(); + + let src = ctx.check_modifications(&["b"], CiEnv::GitHubActions); + assert_eq!(src, modified(sha, &["b"])); + }); +} + +#[test] +fn test_ci_merge_without_upstream_parent_falls_back_to_nightly_ref() { + git_test(|ctx| { + let sha = ctx.create_upstream_merge(&["a"]); + ctx.set_origin_nightly_ref(&sha); + + ctx.create_branch("feature"); + ctx.modify("b"); + ctx.commit(); + ctx.create_branch("nested"); + ctx.modify("c"); + ctx.commit(); + ctx.switch_to_branch("feature"); + ctx.merge("nested", "Tester "); + + let src = ctx.check_modifications(&["d"], CiEnv::GitHubActions); + assert_eq!(src, PathFreshness::LastModifiedUpstream { upstream: sha }); + }); +} + #[test] fn test_local_uncommitted_modifications() { git_test(|ctx| { diff --git a/src/bootstrap/src/utils/tests/git.rs b/src/bootstrap/src/utils/tests/git.rs index d9dd9ab980088..ec25c72af51b1 100644 --- a/src/bootstrap/src/utils/tests/git.rs +++ b/src/bootstrap/src/utils/tests/git.rs @@ -74,6 +74,15 @@ impl GitCtx { self.run_git(&["rev-parse", "--abbrev-ref", "HEAD"]) } + pub fn set_origin_branch_ref(&self, branch: &str, commit: &str) { + let refname = format!("refs/remotes/origin/{branch}"); + self.run_git(&["update-ref", &refname, commit]); + } + + pub fn set_origin_nightly_ref(&self, commit: &str) { + self.set_origin_branch_ref(&self.nightly_branch, commit); + } + pub fn merge(&self, branch: &str, author: &str) { self.run_git(&["merge", "--no-commit", "--no-ff", branch]); self.run_git(&[ diff --git a/src/build_helper/src/git.rs b/src/build_helper/src/git.rs index 87a52eee49b85..64e86a651ab00 100644 --- a/src/build_helper/src/git.rs +++ b/src/build_helper/src/git.rs @@ -70,14 +70,11 @@ pub enum PathFreshness { /// were not modified upstream in the meantime. In that case we would be redownloading CI /// artifacts unnecessarily. /// -/// - In CI, we use a shallow clone of depth 2, i.e., we fetch only a single parent commit -/// (which will be the most recent bors merge commit) and do not have access -/// to the full git history. Luckily, we only need to distinguish between two situations: -/// 1) The current PR made modifications to `target_paths`. -/// In that case, a build is typically necessary. -/// 2) The current PR did not make modifications to `target_paths`. -/// In that case we simply take the latest upstream commit, because on CI there is no need to avoid -/// redownloading. +/// - In CI, we prefer a shallow merge-parent fast path when `HEAD` is a CI-generated merge +/// commit. However, fork push workflows can also run in shallow clones where `HEAD` is just the +/// branch tip, so blindly using `HEAD^1` there would pick a fork commit instead of the upstream +/// base. In those cases we fall back to the fetched nightly branch ref, and only then to the +/// normal upstream search logic. pub fn check_path_modifications( git_dir: &Path, config: &GitConfig<'_>, @@ -90,24 +87,9 @@ pub fn check_path_modifications( } let upstream_sha = if matches!(ci_env, CiEnv::GitHubActions) { - // Here the situation is different for PR CI and try/auto CI. - // For PR CI, we have the following history: - // - // 1-N PR commits - // upstream merge commit made by bors - // - // For try/auto CI, we have the following history: - // <**non-upstream** merge commit made by bors> - // 1-N PR commits - // upstream merge commit made by bors - // - // But on both cases, HEAD should be a merge commit. - // So if HEAD contains modifications of `target_paths`, our PR has modified - // them. If not, we can use the only available upstream commit for downloading - // artifacts. - - // Do not include HEAD, as it is never an upstream commit - // If we do not find an upstream commit in CI, something is seriously wrong. + // CI may be running on a synthetic merge ref or a shallow fork push ref. + // `get_closest_upstream_commit` handles the trusted merge-parent fast path and falls back + // to the fetched nightly branch ref when the merge-parent assumption is not valid. Some( get_closest_upstream_commit(Some(git_dir), config, ci_env)? .expect("No upstream commit was found on CI"), @@ -224,23 +206,45 @@ fn get_latest_upstream_commit_that_modified_files( /// Returns the most recent (ordered chronologically) commit found in the local history that /// should exist upstream. We identify upstream commits by the e-mail of the commit /// author. -/// -/// If we are in CI, we simply return our first parent. pub fn get_closest_upstream_commit( git_dir: Option<&Path>, config: &GitConfig<'_>, env: CiEnv, ) -> Result, String> { - let base = match env { - CiEnv::None => "HEAD", + match env { + CiEnv::None => get_closest_upstream_commit_from_ref(git_dir, config, "HEAD"), CiEnv::GitHubActions => { - // On CI, we should always have a non-upstream merge commit at the tip, - // and our first parent should be the most recently merged upstream commit. - // We thus simply return our first parent. - return resolve_commit_sha(git_dir, "HEAD^1").map(Some); + // CI-generated PR and auto-merge refs put a synthetic merge commit at HEAD, so the + // first parent is usually the most recent upstream merge commit. Fork push workflows + // do not have that shape, though, and in shallow clones `HEAD^1` can just be the + // previous fork commit. Only trust the fast path when it points at an actual upstream + // merge-bot commit, otherwise fall back to the fetched nightly branch. + if is_merge_commit(git_dir, "HEAD")? { + let parent = resolve_commit_sha(git_dir, "HEAD^1")?; + if is_upstream_merge_commit(git_dir, &parent, config)? { + return Ok(Some(parent)); + } + } + + let nightly_ref = format!("refs/remotes/origin/{}", config.nightly_branch); + if git_ref_exists(git_dir, &nightly_ref)? { + if let Some(upstream) = + get_closest_upstream_commit_from_ref(git_dir, config, &nightly_ref)? + { + return Ok(Some(upstream)); + } + } + + get_closest_upstream_commit_from_ref(git_dir, config, "HEAD") } - }; + } +} +fn get_closest_upstream_commit_from_ref( + git_dir: Option<&Path>, + config: &GitConfig<'_>, + base: &str, +) -> Result, String> { let mut git = Command::new("git"); if let Some(git_dir) = git_dir { @@ -272,6 +276,60 @@ pub fn get_closest_upstream_commit( if output.is_empty() { Ok(None) } else { Ok(Some(output)) } } +fn is_merge_commit(git_dir: Option<&Path>, commit_ref: &str) -> Result { + let mut git = Command::new("git"); + if let Some(git_dir) = git_dir { + git.current_dir(git_dir); + } + + let output = git + .args(["rev-parse", "--verify", "--quiet", &format!("{commit_ref}^2")]) + .stderr(Stdio::null()) + .stdout(Stdio::null()) + .status() + .map_err(|e| format!("failed to run command: {git:?}: {e}"))?; + Ok(output.success()) +} + +fn git_ref_exists(git_dir: Option<&Path>, refname: &str) -> Result { + let mut git = Command::new("git"); + if let Some(git_dir) = git_dir { + git.current_dir(git_dir); + } + + let output = git + .args(["rev-parse", "--verify", "--quiet", refname]) + .stderr(Stdio::null()) + .stdout(Stdio::null()) + .status() + .map_err(|e| format!("failed to run command: {git:?}: {e}"))?; + Ok(output.success()) +} + +fn is_upstream_merge_commit( + git_dir: Option<&Path>, + commit_ref: &str, + config: &GitConfig<'_>, +) -> Result { + let mut git = Command::new("git"); + if let Some(git_dir) = git_dir { + git.current_dir(git_dir); + } + + git.args(["show", "-s", "--format=%ae", commit_ref]); + let author_email = output_result(&mut git)?.trim().to_owned(); + let merge_bot_email = extract_author_email(config.git_merge_commit_email); + Ok(author_email == merge_bot_email || author_email == TEMPORARY_BORS_EMAIL) +} + +fn extract_author_email(author: &str) -> &str { + author + .split_once('<') + .and_then(|(_, email)| email.trim().strip_suffix('>')) + .map(str::trim) + .unwrap_or_else(|| author.trim()) +} + /// Resolve the commit SHA of `commit_ref`. fn resolve_commit_sha(git_dir: Option<&Path>, commit_ref: &str) -> Result { let mut git = Command::new("git"); From e8122423f4e6aa6cf5657e3d51dbb033ab3b5a6e Mon Sep 17 00:00:00 2001 From: cypherair <262752927+cypherair@users.noreply.github.com> Date: Fri, 24 Apr 2026 20:04:31 -0700 Subject: [PATCH 182/183] bootstrap: tolerate missing upstream in shallow fork CI Fork push workflows can run in GitHub Actions with only the triggering branch fetched. In that shape refs/remotes/origin/main may be absent, and a shallow feature branch may not contain any bors-authored upstream commit. After the CI upstream detection stopped blindly trusting HEAD^1, that missing upstream case could fall through to searching HEAD and then panic when no upstream commit was found. Treat it as MissingUpstream instead, so download-rustc/download-ci-llvm if-unchanged conservatively disables CI downloads and builds locally. Add a regression test for the shallow fork-push shape without an origin/main ref. --- src/bootstrap/src/core/config/tests.rs | 14 ++++++++++++++ src/build_helper/src/git.rs | 14 +++++++------- 2 files changed, 21 insertions(+), 7 deletions(-) diff --git a/src/bootstrap/src/core/config/tests.rs b/src/bootstrap/src/core/config/tests.rs index 50903f74733c2..805b612a53305 100644 --- a/src/bootstrap/src/core/config/tests.rs +++ b/src/bootstrap/src/core/config/tests.rs @@ -753,6 +753,20 @@ fn test_push_ci_changed_in_branch_uses_nightly_ref() { }); } +#[test] +fn test_push_ci_missing_upstream_returns_missing_upstream() { + git_test(|ctx| { + ctx.create_branch("feature"); + ctx.modify("b"); + ctx.commit(); + ctx.modify("c"); + ctx.commit(); + + let src = ctx.check_modifications(&["d"], CiEnv::GitHubActions); + assert_eq!(src, PathFreshness::MissingUpstream); + }); +} + #[test] fn test_ci_merge_without_upstream_parent_falls_back_to_nightly_ref() { git_test(|ctx| { diff --git a/src/build_helper/src/git.rs b/src/build_helper/src/git.rs index 64e86a651ab00..4308f1dfb1789 100644 --- a/src/build_helper/src/git.rs +++ b/src/build_helper/src/git.rs @@ -49,8 +49,9 @@ pub enum PathFreshness { /// It can be used to figure out if we should download artifacts from CI or rather /// build them locally. /// -/// The function assumes that at least a single upstream bors merge commit is in the -/// local git history. +/// If no upstream bors merge commit can be found in the available local git history, +/// the function returns `MissingUpstream` so callers can conservatively avoid using +/// CI artifacts. /// /// `target_paths` should be a non-empty slice of paths (git `pathspec`s) relative to `git_dir` /// whose modifications would invalidate the artifact. @@ -89,11 +90,10 @@ pub fn check_path_modifications( let upstream_sha = if matches!(ci_env, CiEnv::GitHubActions) { // CI may be running on a synthetic merge ref or a shallow fork push ref. // `get_closest_upstream_commit` handles the trusted merge-parent fast path and falls back - // to the fetched nightly branch ref when the merge-parent assumption is not valid. - Some( - get_closest_upstream_commit(Some(git_dir), config, ci_env)? - .expect("No upstream commit was found on CI"), - ) + // to the fetched nightly branch ref when the merge-parent assumption is not valid. If a + // fork push clone does not have that ref either, conservatively report `MissingUpstream` + // so callers disable CI downloads and build locally instead of panicking. + get_closest_upstream_commit(Some(git_dir), config, ci_env)? } else { // Outside CI, we want to find the most recent upstream commit that // modified the set of paths, to have an upstream reference that does not change From a9d110acd4fc277dc1ec6a30f358eb847f641193 Mon Sep 17 00:00:00 2001 From: cypherair <262752927+cypherair@users.noreply.github.com> Date: Sat, 25 Apr 2026 15:01:58 -0700 Subject: [PATCH 183/183] ci: scope arm64e integration validation to prep patches --- .../workflows/arm64e-upstream-sync-prep.yml | 113 ++++++++++++++++++ .github/workflows/fork-arm64e.yml | 64 ++++++++++ 2 files changed, 177 insertions(+) create mode 100644 .github/workflows/arm64e-upstream-sync-prep.yml create mode 100644 .github/workflows/fork-arm64e.yml diff --git a/.github/workflows/arm64e-upstream-sync-prep.yml b/.github/workflows/arm64e-upstream-sync-prep.yml new file mode 100644 index 0000000000000..4a5ceefa072ac --- /dev/null +++ b/.github/workflows/arm64e-upstream-sync-prep.yml @@ -0,0 +1,113 @@ +name: arm64e Upstream Sync Prep + +on: + workflow_dispatch: + inputs: + integration_branch: + description: CypherAir arm64e integration branch to inspect. + required: true + default: integration/arm64e-upstream-prs + type: string + upstream_ref: + description: Upstream Rust ref to merge in the dry-run workspace. + required: true + default: upstream/main + type: string + create_refresh_pr: + description: Push a refresh branch and open a draft PR when the dry-run merge succeeds. + required: true + default: false + type: boolean +permissions: + contents: write + pull-requests: write + actions: write + +jobs: + sync-prep: + if: github.repository == 'cypherair/rust' + runs-on: ubuntu-latest + defaults: + run: + shell: bash + steps: + - name: Checkout fork + uses: actions/checkout@v5 + with: + fetch-depth: 0 + + - name: Fetch upstream and integration refs + env: + INTEGRATION_BRANCH: ${{ inputs.integration_branch }} + run: | + set -euo pipefail + git remote add upstream https://github.com/rust-lang/rust.git 2>/dev/null || git remote set-url upstream https://github.com/rust-lang/rust.git + git fetch --prune origin \ + "+refs/heads/${INTEGRATION_BRANCH}:refs/remotes/origin/${INTEGRATION_BRANCH}" \ + +refs/heads/main:refs/remotes/origin/main + git fetch --prune upstream +refs/heads/main:refs/remotes/upstream/main + + - name: Report branch posture + env: + INTEGRATION_BRANCH: ${{ inputs.integration_branch }} + UPSTREAM_REF: ${{ inputs.upstream_ref }} + run: | + set -euo pipefail + { + echo "## arm64e upstream sync prep" + echo + echo "- integration branch: \`${INTEGRATION_BRANCH}\`" + echo "- upstream ref: \`${UPSTREAM_REF}\`" + echo "- origin/main: \`$(git rev-parse refs/remotes/origin/main)\`" + echo "- upstream/main: \`$(git rev-parse refs/remotes/upstream/main)\`" + echo "- integration head: \`$(git rev-parse refs/remotes/origin/${INTEGRATION_BRANCH})\`" + echo "- origin/main...upstream/main: \`$(git rev-list --left-right --count refs/remotes/origin/main...refs/remotes/upstream/main)\`" + echo "- integration...upstream: \`$(git rev-list --left-right --count refs/remotes/origin/${INTEGRATION_BRANCH}...${UPSTREAM_REF})\`" + } >> "$GITHUB_STEP_SUMMARY" + + - name: Dry-run merge upstream into integration branch + id: dry_run + env: + INTEGRATION_BRANCH: ${{ inputs.integration_branch }} + UPSTREAM_REF: ${{ inputs.upstream_ref }} + run: | + set -euo pipefail + git config user.name "github-actions[bot]" + git config user.email "41898282+github-actions[bot]@users.noreply.github.com" + git checkout -B arm64e-sync-dry-run "refs/remotes/origin/${INTEGRATION_BRANCH}" + if git merge --no-ff --no-commit "$UPSTREAM_REF"; then + echo "merge_ok=true" >> "$GITHUB_OUTPUT" + git diff --stat --cached || true + git merge --abort || true + else + echo "merge_ok=false" >> "$GITHUB_OUTPUT" + git status --short + exit 1 + fi + + - name: Create refresh branch and draft PR + id: refresh + if: ${{ inputs.create_refresh_pr && steps.dry_run.outputs.merge_ok == 'true' }} + env: + GITHUB_TOKEN: ${{ github.token }} + INTEGRATION_BRANCH: ${{ inputs.integration_branch }} + UPSTREAM_REF: ${{ inputs.upstream_ref }} + run: | + set -euo pipefail + SHORT_SHA="$(git rev-parse --short=7 "refs/remotes/origin/${INTEGRATION_BRANCH}")" + REFRESH_BRANCH="automation/arm64e-refresh-$(date -u +"%Y%m%dT%H%M%SZ")-${SHORT_SHA}" + + git checkout -B "$REFRESH_BRANCH" "refs/remotes/origin/${INTEGRATION_BRANCH}" + git merge --no-ff "$UPSTREAM_REF" -m "Merge ${UPSTREAM_REF} into ${INTEGRATION_BRANCH}" + git push origin "HEAD:refs/heads/${REFRESH_BRANCH}" + + gh pr create \ + --repo "$GITHUB_REPOSITORY" \ + --base "$INTEGRATION_BRANCH" \ + --head "$REFRESH_BRANCH" \ + --title "[automation] Refresh arm64e integration branch from ${UPSTREAM_REF}" \ + --body "Automated dry-run refresh branch for CypherAir arm64e Rust integration. This PR intentionally targets the integration branch and does not force-push it." \ + --draft + + echo "REFRESH_BRANCH=$REFRESH_BRANCH" >> "$GITHUB_ENV" + echo "branch=$REFRESH_BRANCH" >> "$GITHUB_OUTPUT" diff --git a/.github/workflows/fork-arm64e.yml b/.github/workflows/fork-arm64e.yml new file mode 100644 index 0000000000000..deca0786215da --- /dev/null +++ b/.github/workflows/fork-arm64e.yml @@ -0,0 +1,64 @@ +name: Fork arm64e validation + +# Fork-only CypherAir validation. Drop this workflow before proposing the +# upstreamable arm64e prep patches to rust-lang/rust. + +on: + workflow_dispatch: + push: + branches: + - integration/arm64e-upstream-prs + pull_request: + branches: + - main + +permissions: + contents: read + +concurrency: + group: fork-arm64e-${{ github.event.pull_request.number || github.ref }} + cancel-in-progress: true + +jobs: + prep: + if: github.repository == 'cypherair/rust' + name: arm64e prep validation + runs-on: macos-15 + timeout-minutes: 180 + defaults: + run: + shell: bash + steps: + - name: Checkout source + uses: actions/checkout@v5 + with: + fetch-depth: 2 + submodules: recursive + + # CypherAir fork push runs reproduced a shallow-clone case where bootstrap could not + # safely treat HEAD^1 as the upstream nightly base commit. Keep this in sync with src/stage0. + - name: Fetch nightly base ref + run: | + git fetch --no-tags --prune --depth=1 origin \ + +refs/heads/main:refs/remotes/origin/main + + - name: Show environment + run: | + sw_vers + uname -a + git show -s --format='HEAD: %H %P %ae %s' HEAD + git show -s --format='origin/main: %H %P %ae %s' refs/remotes/origin/main + python3 --version + + - name: Check metadata codegen crate + run: | + python3 x.py check compiler/rustc_codegen_ssa --stage 1 + + - name: Run Mach-O metadata subtype test + run: | + python3 x.py test --stage 1 --force-rerun \ + tests/run-make/arm64e-macho-metadata-subtype + + - name: Run bootstrap tests + run: | + python3 x.py test src/bootstrap --stage 1